Skip to content

Commit

Permalink
Simplify inner CSS API, remove css fun completely (was experimental, …
Browse files Browse the repository at this point in the history
…will be redesigned)

(cherry picked from commit cd7691a)
  • Loading branch information
Schahen authored and Oleksandr Karpovich committed Feb 23, 2022
1 parent 2c4da44 commit 4857f55
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 111 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,12 @@ fun AttrsScope<HTMLInputElement>.height(value: Int) =
fun AttrsScope<HTMLInputElement>.width(value: Int) =
attr("width", value.toString()) // image only

fun AttrsScope<HTMLCanvasElement>.width(value: Int) =
attr("width", value.toString())

fun AttrsScope<HTMLCanvasElement>.height(value: Int) =
attr("height", value.toString())

fun AttrsScope<HTMLInputElement>.list(dataListId: String) =
attr("list", dataListId)

Expand Down Expand Up @@ -330,10 +336,3 @@ fun AttrsScope<HTMLTableCellElement>.colspan(value: Int): AttrsScope<HTMLTableCe

fun AttrsScope<HTMLTableCellElement>.rowspan(value: Int): AttrsScope<HTMLTableCellElement> =
attr("rowspan", value.toString())

/* Canvas attributes */
fun AttrsScope<HTMLCanvasElement>.width(value: CSSSizeValue<out CSSUnitLengthOrPercentage>) =
attr("width", value.toString())

fun AttrsScope<HTMLCanvasElement>.height(value: CSSSizeValue<out CSSUnitLengthOrPercentage>) =
attr("height", value.toString())
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class CSSBuilderImpl(
rulesHolder: CSSRulesHolder
) : CSSRuleBuilderImpl(), CSSBuilder, CSSRulesHolder by rulesHolder {
override fun style(selector: CSSSelector, cssRule: CSSBuilder.() -> Unit) {
val resolvedSelector = if (selector.contains(self, true) || selector.contains(currentRoot, true)) {
val resolvedSelector = if (selector.contains(self) || selector.contains(currentRoot)) {
selector
} else {
desc(self, selector)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package org.jetbrains.compose.web.css

import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateListOf
import org.jetbrains.compose.web.ExperimentalComposeWebStyleApi
import org.jetbrains.compose.web.css.selectors.CSSSelector
import org.jetbrains.compose.web.dom.Style
import kotlin.properties.ReadOnlyProperty
Expand Down Expand Up @@ -77,49 +76,32 @@ open class StyleSheet(

@Suppress("EqualsOrHashCode")
internal class CSSSelfSelector(var selector: CSSSelector? = null) : CSSSelector() {
override fun toString(): String = throw IllegalStateException("You can't concatenate `String + CSSSelector` which contains `self` or `root`. Use `selector(<your string>)` to convert `String` to `CSSSelector` for proper work. https://github.com/JetBrains/compose-jb/issues/1440")
override fun asString(): String = selector?.asString() ?: throw IllegalStateException("You can't instantiate self")
override fun toString(): String =
throw IllegalStateException("You can't concatenate `String + CSSSelector` which contains `self` or `root`. Use `selector(<your string>)` to convert `String` to `CSSSelector` for proper work. https://github.com/JetBrains/compose-jb/issues/1440")

override fun asString(): String =
selector?.asString() ?: throw IllegalStateException("You can't instantiate self")

override fun equals(other: Any?): Boolean {
return other is CSSSelfSelector
}
}

// TODO: just proof of concept, do not use it
@ExperimentalComposeWebStyleApi
fun css(cssBuild: CSSBuilder.() -> Unit): String {
val selfSelector = CSSSelfSelector()
val (style, newCssRules) = buildCSS(selfSelector, selfSelector, cssBuild)
val cssRule = cssRules.find {
it is CSSStyleRuleDeclaration &&
it.selector is CSSSelector.CSSClass && it.style == style &&
(boundClasses[it.selector.className] ?: emptyList()) == newCssRules
}.unsafeCast<CSSStyleRuleDeclaration?>()
return if (cssRule != null) {
cssRule.selector.unsafeCast<CSSSelector.CSSClass>().className
} else {
val classNameSelector = CSSSelector.CSSClass("auto-${counter++}")
selfSelector.selector = classNameSelector
add(classNameSelector, style)
newCssRules.forEach { add(it) }
boundClasses[classNameSelector.className] = newCssRules
classNameSelector.className
}
}

protected class CSSHolder(private val usePrefix: Boolean, private val cssBuilder: CSSBuilder.() -> Unit) {
operator fun provideDelegate(
sheet: StyleSheet,
property: KProperty<*>
): ReadOnlyProperty<Any?, String> {
val sheetName = if (usePrefix) "${sheet::class.simpleName}-" else ""
val selector = CSSSelector.CSSClass("$sheetName${property.name}")
val className = "$sheetName${property.name}"
val selector = object : CSSSelector() {
override fun asString() = ".${className}"
}
val (properties, rules) = buildCSS(selector, selector, cssBuilder)
sheet.add(selector, properties)
rules.forEach { sheet.add(it) }

return ReadOnlyProperty { _, _ ->
selector.className
}
return ReadOnlyProperty { _, _ -> className }
}
}

Expand Down Expand Up @@ -156,9 +138,9 @@ internal fun buildCSS(
): Pair<StyleHolder, CSSRuleDeclarationList> {
val styleSheet = StyleSheetBuilderImpl()
// workaround because of problems with plus operator overloading
val root = if (thisClass is StyleSheet.CSSSelfSelector) thisClass else StyleSheet.CSSSelfSelector(thisClass)
val root = (thisClass as? StyleSheet.CSSSelfSelector) ?: StyleSheet.CSSSelfSelector(thisClass)
// workaround because of problems with plus operator overloading
val self = if (thisContext is StyleSheet.CSSSelfSelector) thisContext else StyleSheet.CSSSelfSelector(thisContext)
val self = (thisContext as? StyleSheet.CSSSelfSelector) ?: StyleSheet.CSSSelfSelector(thisContext)

val builder = CSSBuilderImpl(root, self, styleSheet)
builder.cssRule()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,24 +26,25 @@ interface GenericStyleSheetBuilder<TBuilder> : CSSRulesHolder, SelectorsScope {
}

operator fun String.invoke(cssRule: TBuilder.() -> Unit) {
style(Raw(this), cssRule)
style(RawSelector(this), cssRule)
}

infix fun String.style(cssRule: TBuilder.() -> Unit) {
style(Raw(this), cssRule)
style(RawSelector(this), cssRule)
}
}

private val Universal = RawSelector("*")

interface SelectorsScope {
fun selector(selector: String): CSSSelector = Raw(selector)
fun selector(selector: String): CSSSelector = RawSelector(selector)
fun combine(vararg selectors: CSSSelector): CSSSelector = Combine(selectors.toMutableList())

operator fun CSSSelector.plus(selector: CSSSelector): CSSSelector {
if (this is Combine) {
return if (this is Combine) {
this.selectors.add(selector)
return this
}
return if (selector is Combine) {
this
} else if (selector is Combine) {
selector.selectors.add(0, this)
selector
} else {
Expand All @@ -52,12 +53,12 @@ interface SelectorsScope {
}

operator fun CSSSelector.plus(selector: String): CSSSelector {
if (this is Combine) {
return if (this is Combine) {
this.selectors.add(selector(selector))
return this
this
} else {
combine(this, selector(selector))
}

return combine(this, selector(selector))
}

@JsName("returnUniversalSelector")
Expand All @@ -67,9 +68,9 @@ interface SelectorsScope {
val universal: CSSSelector
get() = Universal

fun type(type: String): CSSSelector = Type(type)
fun className(className: String): CSSSelector = CSSSelector.CSSClass(className)
fun id(id: String): CSSSelector = Id(id)
fun type(type: String): CSSSelector = RawSelector(type)
fun className(className: String): CSSSelector = RawSelector(".$className")
fun id(id: String): CSSSelector = RawSelector("#$id")

fun attr(
name: String,
Expand Down Expand Up @@ -241,66 +242,54 @@ interface SelectorsScope {
fun slotted(selector: CSSSelector): CSSSelector = PseudoElementInternal.Slotted(selector)
}

private data class Id(val id: String) : CSSSelector() {
override fun toString(): String = "#$id"
}

private data class Type(val type: String) : CSSSelector() {
override fun toString(): String = type
}

private object Universal : CSSSelector() {
override fun toString(): String = "*"
}

private data class Raw(val selector: String) : CSSSelector() {
private data class RawSelector(val selector: String) : CSSSelector() {
override fun toString(): String = selector
}

private data class Combine(val selectors: MutableList<CSSSelector>) : CSSSelector() {
override fun contains(other: CSSSelector, strict: Boolean): Boolean =
contains(this, other, selectors, strict)
override fun contains(other: CSSSelector): Boolean =
contains(this, other, selectors)

override fun toString(): String = selectors.joinToString("")
override fun asString(): String = selectors.joinToString("") { it.asString() }
}

private data class Group(val selectors: List<CSSSelector>) : CSSSelector() {
override fun contains(other: CSSSelector, strict: Boolean): Boolean =
contains(this, other, selectors, strict)
override fun contains(other: CSSSelector): Boolean =
contains(this, other, selectors)

override fun toString(): String = selectors.joinToString(", ")
override fun asString(): String = selectors.joinToString(", ") { it.asString() }
}

private data class Descendant(val parent: CSSSelector, val selected: CSSSelector) :
CSSSelector() {
override fun contains(other: CSSSelector, strict: Boolean): Boolean =
contains(this, other, listOf(parent, selected), strict)
override fun contains(other: CSSSelector): Boolean =
contains(this, other, listOf(parent, selected))

override fun toString(): String = "$parent $selected"
override fun asString(): String = "${parent.asString()} ${selected.asString()}"
}

private data class Child(val parent: CSSSelector, val selected: CSSSelector) : CSSSelector() {
override fun contains(other: CSSSelector, strict: Boolean): Boolean =
contains(this, other, listOf(parent, selected), strict)
override fun contains(other: CSSSelector): Boolean =
contains(this, other, listOf(parent, selected))

override fun toString(): String = "$parent > $selected"
override fun asString(): String = "${parent.asString()} > ${selected.asString()}"
}

private data class Sibling(val prev: CSSSelector, val selected: CSSSelector) : CSSSelector() {
override fun contains(other: CSSSelector, strict: Boolean): Boolean =
contains(this, other, listOf(prev, selected), strict)
override fun contains(other: CSSSelector): Boolean =
contains(this, other, listOf(prev, selected))

override fun toString(): String = "$prev ~ $selected"
override fun asString(): String = "${prev.asString()} ~ ${selected.asString()}"
}

private data class Adjacent(val prev: CSSSelector, val selected: CSSSelector) : CSSSelector() {
override fun contains(other: CSSSelector, strict: Boolean): Boolean =
contains(this, other, listOf(prev, selected), strict)
override fun contains(other: CSSSelector): Boolean =
contains(this, other, listOf(prev, selected))

override fun toString(): String = "$prev + $selected"
override fun asString(): String = "${prev.asString()} + ${selected.asString()}"
Expand All @@ -327,6 +316,7 @@ private open class PseudoClassInternal(val name: String) : CSSSelector() {
name == other.name && argsStr() == other.argsStr()
} else false
}

open fun argsStr(): String? = null
override fun toString(): String = ":$name${argsStr()?.let { "($it)" } ?: ""}"

Expand All @@ -353,16 +343,16 @@ private open class PseudoClassInternal(val name: String) : CSSSelector() {
}

class Host internal constructor(val selector: CSSSelector) : PseudoClassInternal("host") {
override fun contains(other: CSSSelector, strict: Boolean): Boolean =
contains(this, other, listOf(selector), strict)
override fun contains(other: CSSSelector): Boolean =
contains(this, other, listOf(selector))

override fun argsStr() = selector.asString()
}

// Etc
class Not internal constructor(val selector: CSSSelector) : PseudoClassInternal("not") {
override fun contains(other: CSSSelector, strict: Boolean): Boolean =
contains(this, other, listOf(selector), strict)
override fun contains(other: CSSSelector): Boolean =
contains(this, other, listOf(selector))

override fun argsStr() = "$selector"
}
Expand All @@ -379,8 +369,8 @@ private open class PseudoElementInternal(val name: String) : CSSSelector() {
override fun toString(): String = "::$name${argsStr()?.let { "($it)" } ?: ""}"

class Slotted internal constructor(val selector: CSSSelector) : PseudoElementInternal("slotted") {
override fun contains(other: CSSSelector, strict: Boolean): Boolean =
contains(this, other, listOf(selector), strict)
override fun contains(other: CSSSelector): Boolean =
contains(this, other, listOf(selector))

override fun argsStr() = selector.asString()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,31 +35,21 @@ sealed interface Nth {
}

abstract class CSSSelector internal constructor() {
override fun equals(other: Any?): Boolean {
return this === other || asString() == (other as? CSSSelector)?.asString()
}

internal open fun contains(other: CSSSelector, strict: Boolean = false): Boolean {
return if (strict) this === other else this == other
internal open fun contains(other: CSSSelector): Boolean {
return this === other
}

@Suppress("SuspiciousEqualsCombination")
protected fun contains(that: CSSSelector, other: CSSSelector, children: List<CSSSelector>, strict: Boolean): Boolean {
return that === other || // exactly same selector
children.any { it.contains(other, strict) } || // contains it in children
(!strict && that == other) // equals structurally
protected fun contains(that: CSSSelector, other: CSSSelector, children: List<CSSSelector>): Boolean {
return (that === other) || children.any { it.contains(other) }
}


// This method made for workaround because of possible concatenation of `String + CSSSelector`,
// so `toString` is called for such operator, but we are calling `asString` for instantiation.
// `toString` is reloaded for CSSSelfSelector
internal open fun asString(): String = toString()

internal data class CSSClass internal constructor(val className: String) : CSSSelector() {
override fun toString(): String = ".$className"
}

object Attribute {
enum class Operator(val value: String) {
Equals("="),
Expand Down
8 changes: 4 additions & 4 deletions web/core/src/jsTest/kotlin/elements/AttributesTests.kt
Original file line number Diff line number Diff line change
Expand Up @@ -553,15 +553,15 @@ class AttributesTests {
fun canvasAttributeTest() = runTest {
composition {
Canvas({
height(400.px)
width(450.px)
height(400)
width(450)
})
}
with(nextChild() as HTMLCanvasElement) {
val attrsMap = getAttributeNames().associateWith { getAttribute(it) }
assertEquals(2, attrsMap.size)
assertEquals("450px", attrsMap["width"])
assertEquals("400px", attrsMap["height"])
assertEquals("450", attrsMap["width"])
assertEquals("400", attrsMap["height"])
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -249,16 +249,8 @@ fun main() {

Div(
attrs = {
classes(
Auto.css {
color(Color.pink)
hover(self) style {
color(Color.blue)
}
}
)

style {
color(Color.pink)
opacity(30.percent)
}
}
Expand Down

0 comments on commit 4857f55

Please sign in to comment.