Browse Source

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

pull/764/head 0.5.0-build219
Shagen Ogandzhanian 4 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 wtColorGreyLight by variable<Color>()
val wtColorGreyDark by variable<Color>() val wtColorGreyDark by variable<Color>()
val wtOffsetTopUnit by variable<CSSSizeValue>() val wtOffsetTopUnit by variable<CSSUnitValue>()
val wtHorizontalLayoutGutter by variable<CSSSizeValue>() val wtHorizontalLayoutGutter by variable<CSSUnitValue>()
val wtFlowUnit by variable<CSSSizeValue>() val wtFlowUnit by variable<CSSUnitValue>()
val wtHeroFontSize by variable<CSSSizeValue>() val wtHeroFontSize by variable<CSSUnitValue>()
val wtHeroLineHeight by variable<CSSSizeValue>() val wtHeroLineHeight by variable<CSSUnitValue>()
val wtSubtitle2FontSize by variable<CSSSizeValue>() val wtSubtitle2FontSize by variable<CSSUnitValue>()
val wtSubtitle2LineHeight by variable<CSSSizeValue>() val wtSubtitle2LineHeight by variable<CSSUnitValue>()
val wtH2FontSize by variable<CSSSizeValue>() val wtH2FontSize by variable<CSSUnitValue>()
val wtH2LineHeight by variable<CSSSizeValue>() val wtH2LineHeight by variable<CSSUnitValue>()
val wtH3FontSize by variable<CSSSizeValue>() val wtH3FontSize by variable<CSSUnitValue>()
val wtH3LineHeight by variable<CSSSizeValue>() val wtH3LineHeight by variable<CSSUnitValue>()
val wtColCount by variable<Int>() 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 import org.jetbrains.compose.web.css.selectors.CSSSelector
fun <TBuilder> GenericStyleSheetBuilder<TBuilder>.mediaMaxWidth( fun <TBuilder> GenericStyleSheetBuilder<TBuilder>.mediaMaxWidth(
value: CSSSizeValue, value: CSSUnitValue,
cssSelector: CSSSelector, cssSelector: CSSSelector,
rulesBuild: TBuilder.() -> Unit 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) mediaMaxWidth(value, self, builder)
} }

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

@ -1,28 +1,24 @@
package com.sample.style package com.sample.style
import androidx.compose.runtime.Composable
import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.css.*
import org.jetbrains.compose.web.css.selectors.* 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 { object AppCSSVariables : CSSVariables {
val wtColorGreyLight by variable<Color>() val wtColorGreyLight by variable<Color>()
val wtColorGreyDark by variable<Color>() val wtColorGreyDark by variable<Color>()
val wtOffsetTopUnit by variable<CSSSizeValue>() val wtOffsetTopUnit by variable<CSSUnitValue>()
val wtHorizontalLayoutGutter by variable<CSSSizeValue>() val wtHorizontalLayoutGutter by variable<CSSUnitValue>()
val wtFlowUnit by variable<CSSSizeValue>() val wtFlowUnit by variable<CSSUnitValue>()
val wtHeroFontSize by variable<CSSSizeValue>() val wtHeroFontSize by variable<CSSUnitValue>()
val wtHeroLineHeight by variable<CSSSizeValue>() val wtHeroLineHeight by variable<CSSUnitValue>()
val wtSubtitle2FontSize by variable<CSSSizeValue>() val wtSubtitle2FontSize by variable<CSSUnitValue>()
val wtSubtitle2LineHeight by variable<CSSSizeValue>() val wtSubtitle2LineHeight by variable<CSSUnitValue>()
val wtH2FontSize by variable<CSSSizeValue>() val wtH2FontSize by variable<CSSUnitValue>()
val wtH2LineHeight by variable<CSSSizeValue>() val wtH2LineHeight by variable<CSSUnitValue>()
val wtH3FontSize by variable<CSSSizeValue>() val wtH3FontSize by variable<CSSUnitValue>()
val wtH3LineHeight by variable<CSSSizeValue>() val wtH3LineHeight by variable<CSSUnitValue>()
val wtColCount by variable<Int>() 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 package com.sample.style
import androidx.compose.runtime.Composable
import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.css.*
import org.jetbrains.compose.web.css.selectors.* 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( fun <TBuilder> GenericStyleSheetBuilder<TBuilder>.mediaMaxWidth(
value: CSSSizeValue, value: CSSUnitValue,
cssSelector: CSSSelector, cssSelector: CSSSelector,
rulesBuild: TBuilder.() -> Unit 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) 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.asNumber() = this.asDynamic() as? Number
fun CSSNumberish.asCSSNumericValue(): CSSNumericValue? = this.asDynamic() as? CSSNumericValueJS fun CSSNumberish.asCSSNumericValue(): CSSNumericValue? = this.asDynamic() as? CSSNumericValue
// declare enum CSSNumericBaseType { // declare enum CSSNumericBaseType {
// 'length', // 'length',
@ -124,47 +124,7 @@ val CSSNumericType.percentHint
get() = CSSNumericBaseType.valueOf(this.asDynamic().percentHint) get() = CSSNumericBaseType.valueOf(this.asDynamic().percentHint)
// set(value) { this.asDynamic().percentHint = value.value } // set(value) { this.asDynamic().percentHint = value.value }
external interface CSSNumericValue : CSSStyleValue { 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
}
// declare enum CSSMathOperator { // declare enum CSSMathOperator {
// 'sum', // 'sum',
@ -185,9 +145,7 @@ enum class CSSMathOperator(val value: String) {
clamp("clamp") clamp("clamp")
} }
open external class CSSMathValue : CSSNumericValueJS { open external class CSSMathValue : CSSNumericValue
// readonly operator: CSSMathOperator
}
val CSSMathValue.operator val CSSMathValue.operator
get() = CSSMathOperator.valueOf(this.asDynamic().operator) get() = CSSMathOperator.valueOf(this.asDynamic().operator)
@ -217,16 +175,6 @@ external class CSSMathMax(vararg args: CSSNumberish) : CSSMathValue {
val values: CSSNumericArray 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 { external class CSSNumericArray {
// TODO: [Symbol.iterator]() : IterableIterator<CSSNumericValue> // TODO: [Symbol.iterator]() : IterableIterator<CSSNumericValue>
fun forEach(handler: (CSSNumericValue) -> Unit) fun forEach(handler: (CSSNumericValue) -> Unit)
@ -340,6 +288,7 @@ external interface StylePropertyValue
fun String.asStylePropertyValue() = unsafeCast<StylePropertyValue>() fun String.asStylePropertyValue() = unsafeCast<StylePropertyValue>()
fun Number.asStylePropertyValue() = unsafeCast<StylePropertyValue>() fun Number.asStylePropertyValue() = unsafeCast<StylePropertyValue>()
fun CSSStyleValue.asStylePropertyValue() = unsafeCast<StylePropertyValue>() fun CSSStyleValue.asStylePropertyValue() = unsafeCast<StylePropertyValue>()
fun CSSUnitValue.asStylePropertyValue() = asString().asStylePropertyValue()
external class StylePropertyMap : StylePropertyMapReadOnly { external class StylePropertyMap : StylePropertyMapReadOnly {
fun set(property: String, vararg values: StylePropertyValue) fun set(property: String, vararg values: StylePropertyValue)
@ -351,51 +300,5 @@ external class StylePropertyMap : StylePropertyMapReadOnly {
inline fun Element.computedStyleMap(): StylePropertyMapReadOnly = inline fun Element.computedStyleMap(): StylePropertyMapReadOnly =
this.asDynamic().computedStyleMap().unsafeCast<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") @Suppress("unused")
val cssTypedOMPolyfill = CSSTypedOMPolyfill.default(window) 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 query: CSSMediaQuery.Invertible
) = CSSMediaQuery.Not(query) ) = CSSMediaQuery.Not(query)
fun <TBuilder> GenericStyleSheetBuilder<TBuilder>.minWidth(value: CSSSizeValue) = fun <TBuilder> GenericStyleSheetBuilder<TBuilder>.minWidth(value: CSSUnitValue) =
CSSMediaQuery.MediaFeature("min-width", value.asStylePropertyValue()) 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()) 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()) 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()) 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()) 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)) property("opacity", value(value.value as Double / 100))
} }
@ -193,7 +193,7 @@ class CSSBorder : CustomStyleValue {
var style: StylePropertyValue? = null var style: StylePropertyValue? = null
var color: StylePropertyValue? = null var color: StylePropertyValue? = null
fun width(size: CSSSizeValue) { fun width(size: CSSUnitValue) {
width = size.asStylePropertyValue() width = size.asStylePropertyValue()
} }
@ -227,7 +227,7 @@ inline fun StyleBuilder.border(crossinline borderBuild: CSSBorder.() -> Unit) {
} }
fun StyleBuilder.border( fun StyleBuilder.border(
width: CSSSizeValue? = null, width: CSSUnitValue? = null,
style: LineStyle? = null, style: LineStyle? = null,
color: Color? = null color: Color? = null
) { ) {
@ -291,97 +291,100 @@ fun StyleBuilder.position(position: Position) {
) )
} }
fun StyleBuilder.borderRadius(r: CSSSizeValue) { fun StyleBuilder.borderRadius(r: CSSUnitValue) {
property("border-radius", r.toString().asStylePropertyValue()) property("border-radius", r.asStylePropertyValue())
} }
fun StyleBuilder.borderRadius(topLeft: CSSSizeValue, bottomRight: CSSSizeValue) { fun StyleBuilder.borderRadius(topLeft: CSSUnitValue, bottomRight: CSSUnitValue) {
property("border-radius", "$topLeft $bottomRight".asStylePropertyValue()) property("border-radius", "${topLeft.asString()} ${bottomRight.asString()}".asStylePropertyValue())
} }
fun StyleBuilder.borderRadius( fun StyleBuilder.borderRadius(
topLeft: CSSSizeValue, topLeft: CSSUnitValue,
topRightAndBottomLeft: CSSSizeValue, topRightAndBottomLeft: CSSUnitValue,
bottomRight: CSSSizeValue bottomRight: CSSUnitValue
) { ) {
property("border-radius", "$topLeft $topRightAndBottomLeft $bottomRight".asStylePropertyValue()) property("border-radius", "${topLeft.asString()} ${topRightAndBottomLeft.asString()} ${bottomRight.asString()}".asStylePropertyValue())
} }
fun StyleBuilder.borderRadius( fun StyleBuilder.borderRadius(
topLeft: CSSSizeValue, topLeft: CSSUnitValue,
topRight: CSSSizeValue, topRight: CSSUnitValue,
bottomRight: CSSSizeValue, bottomRight: CSSUnitValue,
bottomLeft: CSSSizeValue 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) { fun StyleBuilder.width(value: CSSUnitValue) {
property("width", value) property("width", value.asStylePropertyValue())
} }
fun StyleBuilder.width(value: CSSAutoValue) { fun StyleBuilder.width(value: CSSAutoValue) {
property("width", value) property("width", value)
} }
fun StyleBuilder.height(value: CSSSizeValue) { fun StyleBuilder.height(value: CSSUnitValue) {
property("height", value) property("height", value.asStylePropertyValue())
} }
fun StyleBuilder.height(value: CSSAutoValue) { fun StyleBuilder.height(value: CSSAutoValue) {
property("height", value) property("height", value)
} }
fun StyleBuilder.top(value: CSSSizeValue) { fun StyleBuilder.top(value: CSSUnitValue) {
property("top", value) property("top", value.asStylePropertyValue())
} }
fun StyleBuilder.top(value: CSSAutoValue) { fun StyleBuilder.top(value: CSSAutoValue) {
property("top", value) property("top", value)
} }
fun StyleBuilder.bottom(value: CSSSizeValue) { fun StyleBuilder.bottom(value: CSSUnitValue) {
property("bottom", value) property("bottom", value.asStylePropertyValue())
} }
fun StyleBuilder.bottom(value: CSSAutoValue) { fun StyleBuilder.bottom(value: CSSAutoValue) {
property("bottom", value) property("bottom", value)
} }
fun StyleBuilder.left(value: CSSSizeValue) { fun StyleBuilder.left(value: CSSUnitValue) {
property("left", value) property("left", value.asStylePropertyValue())
} }
fun StyleBuilder.left(value: CSSAutoValue) { fun StyleBuilder.left(value: CSSAutoValue) {
property("left", value) property("left", value)
} }
fun StyleBuilder.right(value: CSSSizeValue) { fun StyleBuilder.right(value: CSSUnitValue) {
property("right", value) property("right", value.asStylePropertyValue())
} }
fun StyleBuilder.right(value: CSSAutoValue) { fun StyleBuilder.right(value: CSSAutoValue) {
property("right", value) property("right", value)
} }
fun StyleBuilder.fontSize(value: CSSSizeValue) { fun StyleBuilder.fontSize(value: CSSUnitValue) {
property("font-size", value(value)) property("font-size", value(value))
} }
fun StyleBuilder.margin(value: CSSSizeValue) { fun StyleBuilder.margin(value: CSSUnitValue) {
// marign hasn't Typed OM yet // marign hasn't Typed OM yet
property("margin", value(value.toString())) property("margin", value(value.asString()))
} }
fun StyleBuilder.marginLeft(value: CSSSizeValue) { fun StyleBuilder.marginLeft(value: CSSUnitValue) {
property("margin-left", value(value.toString())) property("margin-left", value(value.asString()))
} }
fun StyleBuilder.marginTop(value: CSSSizeValue) { fun StyleBuilder.marginTop(value: CSSUnitValue) {
property("margin-top", value(value.toString())) property("margin-top", value(value.asString()))
} }
fun StyleBuilder.padding(value: CSSSizeValue) { fun StyleBuilder.padding(value: CSSUnitValue) {
// padding hasn't Typed OM yet // 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 package org.jetbrains.compose.web.css
interface CSSSizeValue : CSSUnitValue, StylePropertyValue interface CSSSizeValue<out T : CSSUnit> : CSSNumericValue {
val value: Float
interface CSSRelValue : CSSSizeValue val unit: T
interface CSSpercentValue : CSSRelValue fun asString(): String = "${value}${unit.value}"
interface CSSemValue : CSSRelValue fun newUnit(value: Float): CSSSizeValue<T>
interface CSSexValue : CSSRelValue }
interface CSSchValue : CSSRelValue
interface CSSicValue : CSSRelValue private data class CSSUnitValueTyped<out T : CSSUnit>(
interface CSSremValue : CSSRelValue override val value: Float,
interface CSSlhValue : CSSRelValue override val unit: T
interface CSSrlhValue : CSSRelValue ) : CSSSizeValue<T> {
interface CSSvwValue : CSSRelValue override fun newUnit(value: Float): CSSSizeValue<T> = copy(value = value)
interface CSSvhValue : CSSRelValue }
interface CSSviValue : CSSRelValue
interface CSSvbValue : CSSRelValue operator fun <T : CSSUnit> CSSSizeValue<T>.times(num: Number): CSSSizeValue<T> = newUnit(value * num.toFloat())
interface CSSvminValue : CSSRelValue operator fun <T : CSSUnit> Number.times(unit: CSSSizeValue<T>): CSSSizeValue<T> = unit.newUnit(unit.value * toFloat())
interface CSSvmaxValue : CSSRelValue
interface CSScmValue : CSSRelValue operator fun <T : CSSUnit> CSSSizeValue<T>.div(num: Number): CSSSizeValue<T> = newUnit(value / num.toFloat())
interface CSSmmValue : CSSRelValue
interface CSSQValue : CSSRelValue 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)
interface CSSAbsValue : CSSSizeValue
interface CSSptValue : CSSAbsValue
interface CSSpcValue : CSSAbsValue typealias CSSUnitValue = CSSSizeValue<CSSUnit>
interface CSSpxValue : CSSAbsValue typealias CSSpxValue = CSSSizeValue<CSSUnit.px>
interface CSSangleValue : CSSUnitValue interface CSSUnitRel : CSSUnit
interface CSSdegValue : CSSangleValue interface CSSUnitAbs: CSSUnit
interface CSSgradValue : CSSangleValue interface CSSUnitAngle: CSSUnit
interface CSSradValue : CSSangleValue interface CSSUnitTime: CSSUnit
interface CSSturnValue : CSSangleValue interface CSSUnitFrequency: CSSUnit
interface CSSUnitResolution: CSSUnit
interface CSSTimeValue : CSSUnitValue interface CSSUnitFlex: CSSUnit
interface CSSsValue : CSSTimeValue
interface CSSmsValue : CSSTimeValue typealias CSSAngleValue = CSSSizeValue<CSSUnitAngle>
interface CSSFrequencyValue : CSSUnitValue sealed interface CSSUnit {
interface CSSHzValue : CSSFrequencyValue val value: String
interface CSSkHzValue : CSSFrequencyValue
object percent: CSSUnitRel {
interface CSSResolutionValue : CSSUnitValue override val value: String = "%"
interface CSSdpiValue : CSSResolutionValue }
interface CSSdpcmValue : CSSResolutionValue
interface CSSdppxValue : CSSResolutionValue object em: CSSUnitRel {
override val value = "em"
interface CSSFlexValue : CSSUnitValue }
interface CSSfrValue : CSSFlexValue
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 val Number.number
get(): CSSUnitValue = CSS.number(this) get(): CSSSizeValue<CSSUnit.number> = CSSUnitValueTyped(this.toFloat(), CSSUnit.number)
val Number.percent val Number.percent
get(): CSSpercentValue = CSS.percent(this) get() : CSSSizeValue<CSSUnit.percent> = CSSUnitValueTyped(this.toFloat(), CSSUnit.percent)
val Number.em val Number.em
get(): CSSemValue = CSS.em(this) get() : CSSSizeValue<CSSUnit.em> = CSSUnitValueTyped(this.toFloat(), CSSUnit.em)
val Number.ex val Number.ex
get(): CSSexValue = CSS.ex(this) get(): CSSSizeValue<CSSUnit.ex> = CSSUnitValueTyped(this.toFloat(), CSSUnit.ex)
val Number.ch val Number.ch
get(): CSSchValue = CSS.ch(this) get(): CSSSizeValue<CSSUnit.ch> = CSSUnitValueTyped(this.toFloat(), CSSUnit.ch)
val Number.cssRem val Number.cssRem
get(): CSSremValue = CSS.rem(this) get(): CSSSizeValue<CSSUnit.rem> = CSSUnitValueTyped(this.toFloat(), CSSUnit.rem)
val Number.vw val Number.vw
get(): CSSvwValue = CSS.vw(this) get(): CSSSizeValue<CSSUnit.vw> = CSSUnitValueTyped(this.toFloat(), CSSUnit.vw)
val Number.vh val Number.vh
get(): CSSvhValue = CSS.vh(this) get(): CSSSizeValue<CSSUnit.vh> = CSSUnitValueTyped(this.toFloat(), CSSUnit.vh)
val Number.vmin val Number.vmin
get(): CSSvminValue = CSS.vmin(this) get(): CSSSizeValue<CSSUnit.vmin> = CSSUnitValueTyped(this.toFloat(), CSSUnit.vmin)
val Number.vmax val Number.vmax
get(): CSSvmaxValue = CSS.vmax(this) get(): CSSSizeValue<CSSUnit.vmax> = CSSUnitValueTyped(this.toFloat(), CSSUnit.vmax)
val Number.cm val Number.cm
get(): CSScmValue = CSS.cm(this) get(): CSSSizeValue<CSSUnit.cm> = CSSUnitValueTyped(this.toFloat(), CSSUnit.cm)
val Number.mm val Number.mm
get(): CSSmmValue = CSS.mm(this) get(): CSSSizeValue<CSSUnit.mm> = CSSUnitValueTyped(this.toFloat(), CSSUnit.mm)
val Number.Q val Number.Q
get(): CSSQValue = CSS.Q(this) get() : CSSSizeValue<CSSUnit.q> = CSSUnitValueTyped(this.toFloat(), CSSUnit.q)
val Number.pt val Number.pt
get(): CSSptValue = CSS.pt(this) get(): CSSSizeValue<CSSUnit.pt> = CSSUnitValueTyped(this.toFloat(), CSSUnit.pt)
val Number.pc val Number.pc
get(): CSSpcValue = CSS.pc(this) get(): CSSSizeValue<CSSUnit.pc> = CSSUnitValueTyped(this.toFloat(), CSSUnit.pc)
val Number.px val Number.px
get(): CSSpxValue = CSS.px(this) get(): CSSSizeValue<CSSUnit.px> = CSSUnitValueTyped(this.toFloat(), CSSUnit.px)
val Number.deg val Number.deg
get(): CSSdegValue = CSS.deg(this) get(): CSSSizeValue<CSSUnit.deg> = CSSUnitValueTyped(this.toFloat(), CSSUnit.deg)
val Number.grad val Number.grad
get(): CSSgradValue = CSS.grad(this) get(): CSSSizeValue<CSSUnit.grad> = CSSUnitValueTyped(this.toFloat(), CSSUnit.grad)
val Number.rad val Number.rad
get(): CSSradValue = CSS.rad(this) get(): CSSSizeValue<CSSUnit.rad> = CSSUnitValueTyped(this.toFloat(), CSSUnit.rad)
val Number.turn val Number.turn
get(): CSSturnValue = CSS.turn(this) get(): CSSSizeValue<CSSUnit.turn> = CSSUnitValueTyped(this.toFloat(), CSSUnit.turn)
val Number.s val Number.s
get(): CSSsValue = CSS.s(this) get(): CSSSizeValue<CSSUnit.s> = CSSUnitValueTyped(this.toFloat(), CSSUnit.s)
val Number.ms val Number.ms
get(): CSSmsValue = CSS.ms(this) get(): CSSSizeValue<CSSUnit.ms> = CSSUnitValueTyped(this.toFloat(), CSSUnit.ms)
val Number.Hz val Number.Hz
get(): CSSHzValue = CSS.Hz(this) get(): CSSSizeValue<CSSUnit.hz> = CSSUnitValueTyped(this.toFloat(), CSSUnit.hz)
val Number.kHz val Number.kHz
get(): CSSkHzValue = CSS.kHz(this) get(): CSSSizeValue<CSSUnit.khz> = CSSUnitValueTyped(this.toFloat(), CSSUnit.khz)
val Number.dpi val Number.dpi
get(): CSSdpiValue = CSS.dpi(this) get(): CSSSizeValue<CSSUnit.dpi> = CSSUnitValueTyped(this.toFloat(), CSSUnit.dpi)
val Number.dpcm val Number.dpcm
get(): CSSdpcmValue = CSS.dpcm(this) get(): CSSSizeValue<CSSUnit.dpcm> = CSSUnitValueTyped(this.toFloat(), CSSUnit.dpcm)
val Number.dppx val Number.dppx
get(): CSSdppxValue = CSS.dppx(this) get(): CSSSizeValue<CSSUnit.dppx> = CSSUnitValueTyped(this.toFloat(), CSSUnit.dppx)
val Number.fr 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)" 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) 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) 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 { companion object {

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

@ -5,27 +5,29 @@
package org.jetbrains.compose.web.core.tests 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.ch
import org.jetbrains.compose.web.css.cm import org.jetbrains.compose.web.css.cm
import org.jetbrains.compose.web.css.cssRem import org.jetbrains.compose.web.css.cssRem
import org.jetbrains.compose.web.css.deg 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.dpcm
import org.jetbrains.compose.web.css.dpi import org.jetbrains.compose.web.css.dpi
import org.jetbrains.compose.web.css.dppx import org.jetbrains.compose.web.css.dppx
import org.jetbrains.compose.web.css.em import org.jetbrains.compose.web.css.em
import org.jetbrains.compose.web.css.fr import org.jetbrains.compose.web.css.fr
import org.jetbrains.compose.web.css.grad 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.mm
import org.jetbrains.compose.web.css.ms import org.jetbrains.compose.web.css.ms
import org.jetbrains.compose.web.css.number import org.jetbrains.compose.web.css.number
import org.jetbrains.compose.web.css.pc import org.jetbrains.compose.web.css.pc
import org.jetbrains.compose.web.css.percent 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.pt
import org.jetbrains.compose.web.css.px import org.jetbrains.compose.web.css.px
import org.jetbrains.compose.web.css.rad import org.jetbrains.compose.web.css.rad
import org.jetbrains.compose.web.css.s 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.turn
import org.jetbrains.compose.web.css.vh import org.jetbrains.compose.web.css.vh
import org.jetbrains.compose.web.css.vmax import org.jetbrains.compose.web.css.vmax
@ -37,88 +39,261 @@ import kotlin.test.assertEquals
class CSSUnitApiTests { class CSSUnitApiTests {
// TODO: Cover CSS.Q, CSS.khz and CSS.hz after we'll get rid from polyfill // 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) { @Test
assertEquals(this.value, value, description) fun postfixInvocation() {
assertEquals(this.unit, unit, description) // 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 @Test
private fun CSSUnitValue.assertStructure(otherUnit: CSSUnitValue, description: String? = null) { fun id() {
return assertStructure(otherUnit.value, otherUnit.unit, description) // 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 @Test
fun builderInvocation() { fun arithmeticMultiplicationLeft() {
CSS.number(4).assertStructure(4, "number") assertEquals(16.percent, 4.percent * 4)
CSS.percent(4).assertStructure(4, "percent")
CSS.em(4).assertStructure(4, "em") assertEquals(16.em, 4.em * 4)
CSS.ch(4).assertStructure(4, "ch") assertEquals(16.ch, 4.ch * 4)
CSS.rem(4).assertStructure(4, "rem") assertEquals(16.cssRem, 4.cssRem * 4)
CSS.vw(4).assertStructure(4, "vw") assertEquals(16.vw, 4.vw * 4)
CSS.vh(4).assertStructure(4, "vh") assertEquals(16.vh, 4.vh * 4)
CSS.vmin(4).assertStructure(4, "vmin") assertEquals(16.vmin, 4.vmin * 4)
CSS.vmax(4).assertStructure(4, "vmax") assertEquals(16.vmax, 4.vmax * 4)
CSS.cm(4).assertStructure(4, "cm") assertEquals(16.cm, 4.cm * 4)
CSS.mm(4).assertStructure(4, "mm") assertEquals(16.mm, 4.mm * 4)
CSS.pt(4).assertStructure(4, "pt") assertEquals(16.pt, 4.pt * 4)
CSS.pc(4).assertStructure(4, "pc") assertEquals(16.pc, 4.pc * 4)
CSS.px(4).assertStructure(4, "px") assertEquals(16.px, 4.px * 4)
CSS.deg(4).assertStructure(4, "deg") assertEquals(16.deg, 4.deg * 4)
CSS.grad(4).assertStructure(4, "grad") assertEquals(16.grad, 4.grad * 4)
CSS.rad(4).assertStructure(4, "rad") assertEquals(16.rad, 4.rad * 4)
CSS.turn(4).assertStructure(4, "turn") assertEquals(16.turn, 4.turn * 4)
CSS.s(4).assertStructure(4, "s") assertEquals(16.s, 4.s * 4)
CSS.ms(4).assertStructure(4, "ms") assertEquals(16.ms, 4.ms * 4)
CSS.dpi(4).assertStructure(4, "dpi") assertEquals(16.dpi, 4.dpi * 4)
CSS.dpcm(4).assertStructure(4, "dpcm") assertEquals(16.dpcm, 4.dpcm * 4)
CSS.dppx(4).assertStructure(4, "dppx") assertEquals(16.dppx, 4.dppx * 4)
CSS.fr(4).assertStructure(4, "fr") assertEquals(16.fr, 4.fr * 4)
} }
@Test @Test
fun postfixInvocation() { fun arithmeticDivisionLeft() {
4.number.assertStructure(CSS.number(4), "number postfix") assertEquals(1.percent, 4.percent / 4)
4.percent.assertStructure(CSS.percent(4), "percent posfix")
4.em.assertStructure(CSS.em(4), "em postfix") assertEquals(1.em, 4.em / 4)
4.ch.assertStructure(CSS.ch(4), "ch postfix") 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") assertEquals(1.vw, 4.vw / 4)
4.vh.assertStructure(CSS.vh(4), "vh postfix") assertEquals(1.vh, 4.vh / 4)
4.vmin.assertStructure(CSS.vmin(4), "vmin postfix") assertEquals(1.vmin, 4.vmin / 4)
4.vmax.assertStructure(CSS.vmax(4), "vmax postfix") assertEquals(1.vmax, 4.vmax / 4)
4.cm.assertStructure(CSS.cm(4), "cm postfix") assertEquals(1.cm, 4.cm / 4)
4.mm.assertStructure(CSS.mm(4), "mm postfix") assertEquals(1.mm, 4.mm / 4)
4.pt.assertStructure(CSS.pt(4), "pt postfix") assertEquals(1.pt, 4.pt / 4)
4.pc.assertStructure(CSS.pc(4), "pc postfix") assertEquals(1.pc, 4.pc / 4)
4.px.assertStructure(CSS.px(4), "px postfix") assertEquals(1.px, 4.px / 4)
4.deg.assertStructure(CSS.deg(4), "deg postfix") assertEquals(1.deg, 4.deg / 4)
4.grad.assertStructure(CSS.grad(4), "grad postfix") assertEquals(1.grad, 4.grad / 4)
4.rad.assertStructure(CSS.rad(4), "rad postfix") assertEquals(1.rad, 4.rad / 4)
4.turn.assertStructure(CSS.turn(4), "turn postfix") assertEquals(1.turn, 4.turn / 4)
4.s.assertStructure(CSS.s(4), "s postfix") assertEquals(1.s, 4.s / 4)
4.ms.assertStructure(CSS.ms(4), "ms postfix") assertEquals(1.ms, 4.ms / 4)
4.dpi.assertStructure(CSS.dpi(4), "dpi postfix") assertEquals(1.dpi, 4.dpi / 4)
4.dpcm.assertStructure(CSS.dpcm(4), "dpcm postfix") assertEquals(1.dpcm, 4.dpcm / 4)
4.dppx.assertStructure(CSS.dppx(4), "dppx postfix") 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