Browse Source

[web] Attribute builder builds styles as well

pull/700/head
Shagen Ogandzhanian 3 years ago
parent
commit
6a8e15a7fe
  1. 21
      web/core/src/jsMain/kotlin/androidx/compose/web/attributes/AttrsBuilder.kt
  2. 2
      web/core/src/jsMain/kotlin/androidx/compose/web/attributes/EventsListenerBuilder.kt
  3. 15
      web/core/src/jsMain/kotlin/androidx/compose/web/elements/Base.kt
  4. 111
      web/core/src/jsMain/kotlin/androidx/compose/web/elements/Elements.kt
  5. 1
      web/core/src/jsMain/kotlin/androidx/compose/web/elements/Style.kt
  6. 67
      web/core/src/jsTest/kotlin/InlineStyleTests.kt
  7. 198
      web/core/src/jsTest/kotlin/StaticComposableTests.kt
  8. 6
      web/integration-core/src/jsMain/kotlin/androidx/compose/web/sample/CodeSnippetSamples.kt
  9. 102
      web/integration-core/src/jsMain/kotlin/androidx/compose/web/sample/Sample.kt
  10. 13
      web/integration-core/src/jsMain/kotlin/androidx/compose/web/sample/tests/TestCases1.kt
  11. 16
      web/widgets/src/jsMain/kotlin/Modifier.kt
  12. 2
      web/widgets/src/jsMain/kotlin/layouts/box.kt
  13. 2
      web/widgets/src/jsMain/kotlin/layouts/button.kt
  14. 4
      web/widgets/src/jsMain/kotlin/layouts/column.kt
  15. 4
      web/widgets/src/jsMain/kotlin/layouts/row.kt
  16. 16
      web/widgets/src/jsMain/kotlin/layouts/text.kt

21
web/core/src/jsMain/kotlin/androidx/compose/web/attributes/AttrsBuilder.kt

@ -2,14 +2,21 @@ package androidx.compose.web.attributes
import androidx.compose.runtime.DisposableEffectResult
import androidx.compose.runtime.DisposableEffectScope
import androidx.compose.web.css.StyleBuilder
import androidx.compose.web.css.StyleBuilderImpl
import org.w3c.dom.HTMLElement
class AttrsBuilder<TTag : Tag> : EventsListenerBuilder() {
private val map = mutableMapOf<String, String>()
private val attributesMap = mutableMapOf<String, String>()
val styleBuilder = StyleBuilderImpl()
val propertyUpdates = mutableListOf<Pair<(HTMLElement, Any) -> Unit, Any>>()
var refEffect: (DisposableEffectScope.(HTMLElement) -> DisposableEffectResult)? = null
fun style(builder: StyleBuilder.() -> Unit) {
styleBuilder.apply(builder)
}
inline fun classes(builder: ClassesAttrBuilder.() -> Unit) =
prop(setClassList, ClassesAttrBuilder().apply(builder).asList().toTypedArray())
@ -30,22 +37,22 @@ class AttrsBuilder<TTag : Tag> : EventsListenerBuilder() {
}
fun attr(attr: String, value: String?): AttrsBuilder<TTag> {
if (value == null && attr in map) {
map.remove(attr)
} else if (value != null) {
map[attr] = value
if (value == null) {
attributesMap.remove(attr)
} else {
attributesMap[attr] = value
}
return this
}
@Suppress("UNCHECKED_CAST")
fun <E : HTMLElement, V : Any> prop(update: (E, V) -> Unit, value: V) {
fun <E : HTMLElement, V> prop(update: (E, V) -> Unit, value: V) {
propertyUpdates.add((update to value) as Pair<(HTMLElement, Any) -> Unit, Any>)
}
fun collect(): Map<String, String> {
return map
return attributesMap
}
companion object {

2
web/core/src/jsMain/kotlin/androidx/compose/web/attributes/EventsListenerBuilder.kt

@ -214,7 +214,7 @@ open class EventsListenerBuilder {
listeners.add(DragEventListener(DRAGLEAVE, options, listener))
}
fun asList(): List<WrappedEventListener<*>> = listeners
fun collectListeners(): List<WrappedEventListener<*>> = listeners
fun addEventListener(
eventName: String,

15
web/core/src/jsMain/kotlin/androidx/compose/web/elements/Base.kt

@ -26,7 +26,6 @@ inline fun <TScope, T, reified E : Applier<*>> ComposeDomNode(
noinline factory: () -> T,
elementScope: TScope,
noinline attrsSkippableUpdate: @Composable SkippableUpdater<T>.() -> Unit,
noinline styleSkippableUpdate: @Composable SkippableUpdater<T>.() -> Unit,
content: @Composable TScope.() -> Unit
) {
if (currentComposer.applier !is E) error("Invalid applier")
@ -36,11 +35,11 @@ inline fun <TScope, T, reified E : Applier<*>> ComposeDomNode(
} else {
currentComposer.useNode()
}
// Updater<T>(currentComposer).update()
SkippableUpdater<T>(currentComposer).apply {
attrsSkippableUpdate()
styleSkippableUpdate()
}
currentComposer.startReplaceableGroup(0x7ab4aae9)
content(elementScope)
currentComposer.endReplaceableGroup()
@ -55,7 +54,6 @@ class DisposableEffectHolder(
inline fun <TTag : Tag, THTMLElement : HTMLElement> TagElement(
tagName: String,
crossinline applyAttrs: AttrsBuilder<TTag>.() -> Unit,
crossinline applyStyle: StyleBuilder.() -> Unit,
content: @Composable ElementScope<THTMLElement>.() -> Unit
) {
val scope = remember { ElementScopeImpl<THTMLElement>() }
@ -71,18 +69,13 @@ inline fun <TTag : Tag, THTMLElement : HTMLElement> TagElement(
val attrsApplied = AttrsBuilder<TTag>().also { it.applyAttrs() }
refEffect.effect = attrsApplied.refEffect
val attrsCollected = attrsApplied.collect()
val events = attrsApplied.asList()
val events = attrsApplied.collectListeners()
update {
set(attrsCollected, DomNodeWrapper.UpdateAttrs)
set(events, DomNodeWrapper.UpdateListeners)
set(attrsApplied.propertyUpdates, DomNodeWrapper.UpdateProperties)
}
},
styleSkippableUpdate = {
val style = StyleBuilderImpl().apply(applyStyle)
update {
set(style, DomNodeWrapper.UpdateStyleDeclarations)
set(attrsApplied.styleBuilder, DomNodeWrapper.UpdateStyleDeclarations)
}
},
elementScope = scope,

111
web/core/src/jsMain/kotlin/androidx/compose/web/elements/Elements.kt

@ -43,7 +43,6 @@ import org.w3c.dom.HTMLTextAreaElement
import org.w3c.dom.HTMLUListElement
import org.w3c.dom.Text
typealias StyleBuilderContext = StyleBuilder.() -> Unit
typealias AttrBuilderContext<T> = AttrsBuilder<T>.() -> Unit
typealias ContentBuilder<T> = @Composable ElementScope<T>.() -> Unit
@ -60,13 +59,11 @@ fun Text(value: String) {
@Composable
inline fun Div(
crossinline attrs: AttrBuilderContext<Tag.Div> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLDivElement>
) {
TagElement(
tagName = "div",
applyAttrs = attrs,
applyStyle = style,
content = content
)
}
@ -75,7 +72,6 @@ inline fun Div(
inline fun A(
href: String? = null,
crossinline attrs: AttrBuilderContext<Tag.A> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLAnchorElement>
) {
TagElement<Tag.A, HTMLAnchorElement>(
@ -84,7 +80,6 @@ inline fun A(
href(href)
attrs()
},
applyStyle = style,
content = content
)
}
@ -94,7 +89,6 @@ inline fun Input(
type: InputType = InputType.Text,
value: String = "",
crossinline attrs: AttrBuilderContext<Tag.Input> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLInputElement> = {}
) {
TagElement<Tag.Input, HTMLInputElement>(
@ -104,7 +98,6 @@ inline fun Input(
value(value)
attrs()
},
applyStyle = style,
content = content
)
}
@ -112,135 +105,116 @@ inline fun Input(
@Composable
inline fun Button(
crossinline attrs: AttrBuilderContext<Tag.Button> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLHeadingElement>
) = TagElement("button", applyAttrs = attrs, applyStyle = style, content = content)
) = TagElement("button", applyAttrs = attrs, content = content)
@Composable
inline fun H1(
crossinline attrs: AttrBuilderContext<Tag.H> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLHeadingElement>
) = TagElement("h1", applyAttrs = attrs, applyStyle = style, content = content)
) = TagElement("h1", applyAttrs = attrs, content = content)
@Composable
inline fun H2(
crossinline attrs: AttrBuilderContext<Tag.H> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLHeadingElement>
) = TagElement("h2", applyAttrs = attrs, applyStyle = style, content = content)
) = TagElement("h2", applyAttrs = attrs, content = content)
@Composable
inline fun H3(
crossinline attrs: AttrBuilderContext<Tag.H> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLHeadingElement>
) = TagElement("h3", applyAttrs = attrs, applyStyle = style, content = content)
) = TagElement("h3", applyAttrs = attrs, content = content)
@Composable
inline fun H4(
crossinline attrs: AttrBuilderContext<Tag.H> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLHeadingElement>
) = TagElement("h4", applyAttrs = attrs, applyStyle = style, content = content)
) = TagElement("h4", applyAttrs = attrs, content = content)
@Composable
inline fun H5(
crossinline attrs: AttrBuilderContext<Tag.H> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLHeadingElement>
) = TagElement("h5", applyAttrs = attrs, applyStyle = style, content = content)
) = TagElement("h5", applyAttrs = attrs, content = content)
@Composable
inline fun H6(
crossinline attrs: AttrBuilderContext<Tag.H> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLHeadingElement>
) = TagElement("h6", applyAttrs = attrs, applyStyle = style, content = content)
) = TagElement("h6", applyAttrs = attrs, content = content)
@Composable
inline fun P(
crossinline attrs: AttrBuilderContext<Tag.P> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLParagraphElement>
) = TagElement("p", applyAttrs = attrs, applyStyle = style, content = content)
) = TagElement("p", applyAttrs = attrs, content = content)
@Composable
inline fun Em(
crossinline attrs: AttrBuilderContext<Tag> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLElement>
) = TagElement("em", applyAttrs = attrs, applyStyle = style, content = content)
) = TagElement("em", applyAttrs = attrs, content = content)
@Composable
inline fun I(
crossinline attrs: AttrBuilderContext<Tag> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLElement>
) = TagElement("i", applyAttrs = attrs, applyStyle = style, content = content)
) = TagElement("i", applyAttrs = attrs, content = content)
@Composable
inline fun B(
crossinline attrs: AttrBuilderContext<Tag> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLElement>
) = TagElement("b", applyAttrs = attrs, applyStyle = style, content = content)
) = TagElement("b", applyAttrs = attrs, content = content)
@Composable
inline fun Small(
crossinline attrs: AttrBuilderContext<Tag> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLElement>
) = TagElement("small", applyAttrs = attrs, applyStyle = style, content = content)
) = TagElement("small", applyAttrs = attrs, content = content)
@Composable
inline fun Span(
crossinline attrs: AttrBuilderContext<Tag.Span> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLSpanElement>
) = TagElement("span", applyAttrs = attrs, applyStyle = style, content = content)
) = TagElement("span", applyAttrs = attrs, content = content)
@Composable
inline fun Br(
crossinline attrs: AttrBuilderContext<Tag.Br> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLBRElement>
) = TagElement("br", applyAttrs = attrs, applyStyle = style, content = content)
) = TagElement("br", applyAttrs = attrs, content = content)
@Composable
inline fun Ul(
crossinline attrs: AttrBuilderContext<Tag.Ul> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLUListElement>,
) = TagElement("ul", applyAttrs = attrs, applyStyle = style, content = content)
) = TagElement("ul", applyAttrs = attrs, content = content)
@Composable
inline fun Ol(
crossinline attrs: AttrBuilderContext<Tag.Ol> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLOListElement>
) = TagElement("ol", applyAttrs = attrs, applyStyle = style, content = content)
) = TagElement("ol", applyAttrs = attrs, content = content)
@Composable
inline fun DOMScope<HTMLOListElement>.Li(
crossinline attrs: AttrBuilderContext<Tag.Li> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLLIElement>
) = TagElement("li", applyAttrs = attrs, applyStyle = style, content = content)
) = TagElement("li", applyAttrs = attrs, content = content)
@Composable
inline fun DOMScope<HTMLUListElement>.Li(
crossinline attrs: AttrBuilderContext<Tag.Li> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLLIElement>
) = TagElement("li", applyAttrs = attrs, applyStyle = style, content = content)
) = TagElement("li", applyAttrs = attrs, content = content)
@Composable
inline fun Img(
src: String,
alt: String = "",
crossinline attrs: AttrBuilderContext<Tag.Img> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLImageElement> = {}
) = TagElement<Tag.Img, HTMLImageElement>(
tagName = "img",
@ -248,14 +222,13 @@ inline fun Img(
src(src).alt(alt)
attrs()
},
applyStyle = style, content = content
content = content
)
@Composable
inline fun Form(
action: String? = null,
crossinline attrs: AttrBuilderContext<Tag.Form> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLFormElement>
) = TagElement<Tag.Form, HTMLFormElement>(
tagName = "form",
@ -263,18 +236,16 @@ inline fun Form(
if (!action.isNullOrEmpty()) action(action)
attrs()
},
applyStyle = style, content = content
content = content
)
@Composable
inline fun Select(
crossinline attrs: AttrBuilderContext<Tag.Select> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLSelectElement>
) = TagElement(
tagName = "select",
applyAttrs = attrs,
applyStyle = style,
content = content
)
@ -282,7 +253,6 @@ inline fun Select(
inline fun DOMScope<HTMLUListElement>.Option(
value: String,
crossinline attrs: AttrBuilderContext<Tag.Option> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLOptionElement>
) = TagElement<Tag.Option, HTMLOptionElement>(
tagName = "option",
@ -290,7 +260,6 @@ inline fun DOMScope<HTMLUListElement>.Option(
value(value)
attrs()
},
applyStyle = style,
content = content
)
@ -298,7 +267,6 @@ inline fun DOMScope<HTMLUListElement>.Option(
inline fun OptGroup(
label: String,
crossinline attrs: AttrBuilderContext<Tag.OptGroup> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLOptGroupElement>
) = TagElement<Tag.OptGroup, HTMLOptGroupElement>(
tagName = "optgroup",
@ -306,34 +274,29 @@ inline fun OptGroup(
label(label)
attrs()
},
applyStyle = style,
content = content
)
@Composable
inline fun Section(
crossinline attrs: AttrBuilderContext<Tag> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLElement>
) = TagElement(
tagName = "section",
applyAttrs = attrs,
applyStyle = style,
content = content
)
@Composable
inline fun TextArea(
crossinline attrs: AttrBuilderContext<Tag.TextArea> = {},
crossinline style: StyleBuilderContext = {},
value: String
) = TagElement<Tag.TextArea, HTMLTextAreaElement>(
tagName = "textarea",
applyAttrs = {
value(value)
attrs()
},
applyStyle = style
}
) {
Text(value)
}
@ -341,25 +304,21 @@ inline fun TextArea(
@Composable
inline fun Nav(
crossinline attrs: AttrBuilderContext<Tag.Nav> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLElement>
) = TagElement(
tagName = "nav",
applyAttrs = attrs,
applyStyle = style,
content = content
)
@Composable
inline fun Pre(
crossinline attrs: AttrBuilderContext<Tag.Pre> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLPreElement>
) {
TagElement(
tagName = "pre",
applyAttrs = attrs,
applyStyle = style,
content = content
)
}
@ -367,13 +326,11 @@ inline fun Pre(
@Composable
inline fun Code(
crossinline attrs: AttrBuilderContext<Tag.Code> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLElement>
) {
TagElement(
tagName = "code",
applyAttrs = attrs,
applyStyle = style,
content = content
)
}
@ -381,13 +338,11 @@ inline fun Code(
@Composable
inline fun Main(
crossinline attrs: AttrBuilderContext<Tag.Div> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLElement> = {}
) {
TagElement<Tag.Div, HTMLAnchorElement>(
tagName = "main",
applyAttrs = attrs,
applyStyle = style,
content = content
)
}
@ -395,13 +350,11 @@ inline fun Main(
@Composable
inline fun Footer(
crossinline attrs: AttrBuilderContext<Tag.Div> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLElement> = {}
) {
TagElement<Tag.Div, HTMLAnchorElement>(
tagName = "footer",
applyAttrs = attrs,
applyStyle = style,
content = content
)
}
@ -410,7 +363,6 @@ inline fun Footer(
inline fun Label(
forId: String? = null,
crossinline attrs: AttrBuilderContext<Tag.Label> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLElement> = {}
) {
TagElement<Tag.Label, HTMLAnchorElement>(
@ -419,7 +371,6 @@ inline fun Label(
forId(forId)
attrs()
},
applyStyle = style,
content = content
)
}
@ -427,13 +378,11 @@ inline fun Label(
@Composable
inline fun Table(
crossinline attrs: AttrBuilderContext<Tag.Table> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLTableElement>
) {
TagElement(
tagName = "table",
applyAttrs = attrs,
applyStyle = style,
content = content
)
}
@ -441,13 +390,11 @@ inline fun Table(
@Composable
inline fun Caption(
crossinline attrs: AttrBuilderContext<Tag.Caption> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLTableCaptionElement>
) {
TagElement(
tagName = "caption",
applyAttrs = attrs,
applyStyle = style,
content = content
)
}
@ -455,13 +402,11 @@ inline fun Caption(
@Composable
inline fun Col(
crossinline attrs: AttrBuilderContext<Tag.Col> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLTableColElement>
) {
TagElement(
tagName = "col",
applyAttrs = attrs,
applyStyle = style,
content = content
)
}
@ -469,13 +414,11 @@ inline fun Col(
@Composable
inline fun Colgroup(
crossinline attrs: AttrBuilderContext<Tag.Colgroup> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLTableColElement>
) {
TagElement(
tagName = "colgroup",
applyAttrs = attrs,
applyStyle = style,
content = content
)
}
@ -483,13 +426,11 @@ inline fun Colgroup(
@Composable
inline fun Tr(
crossinline attrs: AttrBuilderContext<Tag.Tr> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLTableRowElement>
) {
TagElement(
tagName = "tr",
applyAttrs = attrs,
applyStyle = style,
content = content
)
}
@ -497,13 +438,11 @@ inline fun Tr(
@Composable
inline fun Thead(
crossinline attrs: AttrBuilderContext<Tag.Thead> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLTableSectionElement>
) {
TagElement(
tagName = "thead",
applyAttrs = attrs,
applyStyle = style,
content = content
)
}
@ -511,13 +450,11 @@ inline fun Thead(
@Composable
inline fun Th(
crossinline attrs: AttrBuilderContext<Tag.Th> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLTableCellElement>
) {
TagElement(
tagName = "th",
applyAttrs = attrs,
applyStyle = style,
content = content
)
}
@ -525,13 +462,11 @@ inline fun Th(
@Composable
inline fun Td(
crossinline attrs: AttrBuilderContext<Tag.Td> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLTableCellElement>
) {
TagElement(
tagName = "td",
applyAttrs = attrs,
applyStyle = style,
content = content
)
}
@ -539,13 +474,11 @@ inline fun Td(
@Composable
inline fun Tbody(
crossinline attrs: AttrBuilderContext<Tag.Tbody> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLTableSectionElement>
) {
TagElement(
tagName = "tbody",
applyAttrs = attrs,
applyStyle = style,
content = content
)
}
@ -553,13 +486,11 @@ inline fun Tbody(
@Composable
inline fun Tfoot(
crossinline attrs: AttrBuilderContext<Tag.Tfoot> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLTableSectionElement>
) {
TagElement(
tagName = "tfoot",
applyAttrs = attrs,
applyStyle = style,
content = content
)
}

1
web/core/src/jsMain/kotlin/androidx/compose/web/elements/Style.kt

@ -54,7 +54,6 @@ inline fun Style(
applyAttrs = {
applyAttrs()
},
applyStyle = {}
) {
DomSideEffect(cssRules) { style ->
style.sheet?.let { sheet ->

67
web/core/src/jsTest/kotlin/InlineStyleTests.kt

@ -1,7 +1,13 @@
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.web.css.Color
import androidx.compose.web.css.backgroundColor
import androidx.compose.web.css.border
import androidx.compose.web.css.color
import androidx.compose.web.css.opacity
import androidx.compose.web.css.padding
import androidx.compose.web.css.px
import androidx.compose.web.elements.Span
import androidx.compose.web.elements.Text
import kotlin.test.Test
@ -15,11 +21,13 @@ class InlineStyleTests {
var isRed by mutableStateOf(true)
composition {
Span(
style = {
if (isRed) {
color("red")
} else {
color("green")
{
style {
if (isRed) {
color("red")
} else {
color("green")
}
}
}
) {
@ -46,9 +54,11 @@ class InlineStyleTests {
var isRed by mutableStateOf(false)
composition {
Span(
style = {
if (isRed) {
color("red")
{
style {
if (isRed) {
color("red")
}
}
}
) {
@ -75,9 +85,11 @@ class InlineStyleTests {
var isRed by mutableStateOf(true)
composition {
Span(
style = {
if (isRed) {
color("red")
{
style {
if (isRed) {
color("red")
}
}
}
) {
@ -104,9 +116,11 @@ class InlineStyleTests {
var isRed by mutableStateOf(true)
composition {
Span(
style = {
if (isRed) {
color("red")
{
style {
if (isRed) {
color("red")
}
}
}
) {
@ -134,4 +148,27 @@ class InlineStyleTests {
)
}
}
@Test
fun sequentialStyleAccumulation() = runTest {
val k by mutableStateOf(40)
composition {
Span({
style {
opacity(k / 100f)
}
id("container")
style {
padding(k.px)
}
}) {}
}
assertEquals(
expected = "<span id=\"container\" style=\"opacity: 0.4; padding: 40px;\"></span>",
actual = root.innerHTML
)
}
}

198
web/core/src/jsTest/kotlin/StaticComposableTests.kt

@ -94,11 +94,13 @@ class StaticComposableTests {
root = root
) {
Div(
style = {
opacity(0.3)
color("red")
opacity(0.2)
color("green")
{
style {
opacity(0.3)
color("red")
opacity(0.2)
color("green")
}
}
) {}
}
@ -113,13 +115,17 @@ class StaticComposableTests {
root = root
) {
Div(
style = {
property("border", value("1px solid red"))
{
style {
property("border", value("1px solid red"))
}
}
) {}
Div(
style = {
border(3.px, color = Color("green"))
{
style {
border(3.px, color = Color("green"))
}
}
) {}
}
@ -144,13 +150,17 @@ class StaticComposableTests {
root = root
) {
Div(
style = {
order(-4)
{
style {
order(-4)
}
}
) {}
Div(
style = {
order(3)
{
style {
order(3)
}
}
) {}
}
@ -166,23 +176,31 @@ class StaticComposableTests {
root = root
) {
Div(
style = {
flexGrow(3)
{
style {
flexGrow(3)
}
}
) {}
Div(
style = {
flexGrow(2.5)
{
style {
flexGrow(2.5)
}
}
) {}
Div(
style = {
flexGrow(1e2)
{
style {
flexGrow(1e2)
}
}
) {}
Div(
style = {
flexGrow(.6)
{
style {
flexGrow(.6)
}
}
) {}
}
@ -200,23 +218,31 @@ class StaticComposableTests {
root = root
) {
Div(
style = {
flexShrink(3)
{
style {
flexShrink(3)
}
}
) {}
Div(
style = {
flexShrink(2.5)
{
style {
flexShrink(2.5)
}
}
) {}
Div(
style = {
flexShrink(1e2)
{
style {
flexShrink(1e2)
}
}
) {}
Div(
style = {
flexShrink(.6)
{
style {
flexShrink(.6)
}
}
) {}
}
@ -234,8 +260,10 @@ class StaticComposableTests {
root = root
) {
Div(
style = {
width(100.px)
{
style {
width(100.px)
}
}
) {}
}
@ -250,23 +278,31 @@ class StaticComposableTests {
root = root
) {
Div(
style = {
borderRadius(3.px)
{
style {
borderRadius(3.px)
}
}
) {}
Div(
style = {
borderRadius(3.px, 5.px)
{
style {
borderRadius(3.px, 5.px)
}
}
) {}
Div(
style = {
borderRadius(3.px, 5.px, 4.px)
{
style {
borderRadius(3.px, 5.px, 4.px)
}
}
) {}
Div(
style = {
borderRadius(3.px, 5.px, 4.px, 1.px)
{
style {
borderRadius(3.px, 5.px, 4.px, 1.px)
}
}
) {}
}
@ -287,8 +323,10 @@ class StaticComposableTests {
root = root
) {
Div(
style = {
top(100.px)
{
style {
top(100.px)
}
}
) {}
}
@ -303,8 +341,10 @@ class StaticComposableTests {
root = root
) {
Div(
style = {
bottom(100.px)
{
style {
bottom(100.px)
}
}
) {}
}
@ -319,8 +359,10 @@ class StaticComposableTests {
root = root
) {
Div(
style = {
left(100.px)
{
style {
left(100.px)
}
}
) {}
}
@ -335,8 +377,10 @@ class StaticComposableTests {
root = root
) {
Div(
style = {
right(100.px)
{
style {
right(100.px)
}
}
) {}
}
@ -351,8 +395,10 @@ class StaticComposableTests {
root = root
) {
Div(
style = {
height(100.px)
{
style {
height(100.px)
}
}
) {}
}
@ -369,8 +415,10 @@ class StaticComposableTests {
) {
enumValues.forEach { displayStyle ->
Div(
style = {
display(displayStyle)
{
style {
display(displayStyle)
}
}
) { }
}
@ -393,8 +441,10 @@ class StaticComposableTests {
) {
enumValues.forEach { flexDirection ->
Span(
style = {
flexDirection(flexDirection)
{
style {
flexDirection(flexDirection)
}
}
) { }
}
@ -417,8 +467,10 @@ class StaticComposableTests {
) {
enumValues.forEach { flexWrap ->
Span(
style = {
flexWrap(flexWrap)
{
style {
flexWrap(flexWrap)
}
}
) { }
}
@ -443,8 +495,10 @@ class StaticComposableTests {
flexDirections.forEach { flexDirection ->
flexWraps.forEach { flexWrap ->
Span(
style = {
flexFlow(flexDirection, flexWrap)
{
style {
flexFlow(flexDirection, flexWrap)
}
}
) { }
}
@ -470,8 +524,10 @@ class StaticComposableTests {
) {
enumValues.forEach { justifyContent ->
Span(
style = {
justifyContent(justifyContent)
{
style {
justifyContent(justifyContent)
}
}
) { }
}
@ -494,8 +550,10 @@ class StaticComposableTests {
) {
enumValues.forEach { alignSelf ->
Span(
style = {
alignSelf(alignSelf)
{
style {
alignSelf(alignSelf)
}
}
) { }
}
@ -518,8 +576,10 @@ class StaticComposableTests {
) {
enumValues.forEach { alignItems ->
Span(
style = {
alignItems(alignItems)
{
style {
alignItems(alignItems)
}
}
) { }
}
@ -542,8 +602,10 @@ class StaticComposableTests {
) {
enumValues.forEach { alignContent ->
Span(
style = {
alignContent(alignContent)
{
style {
alignContent(alignContent)
}
}
) { }
}
@ -566,8 +628,10 @@ class StaticComposableTests {
) {
enumValues.forEach { position ->
Span(
style = {
position(position)
{
style {
position(position)
}
}
) { }
}

6
web/integration-core/src/jsMain/kotlin/androidx/compose/web/sample/CodeSnippetSamples.kt

@ -20,8 +20,10 @@ fun KotlinCodeSnippets() {
val currentSnippet = remember { mutableStateOf("") }
Div(
style = {
padding(5.px)
{
style {
padding(5.px)
}
}
) {
H4 {

102
web/integration-core/src/jsMain/kotlin/androidx/compose/web/sample/Sample.kt

@ -14,16 +14,26 @@ import androidx.compose.web.attributes.name
import androidx.compose.web.css.CSSVariables
import androidx.compose.web.css.Color
import androidx.compose.web.css.LineStyle
import androidx.compose.web.css.selectors.className
import androidx.compose.web.css.Style
import androidx.compose.web.css.StyleSheet
import androidx.compose.web.css.and
import androidx.compose.web.css.backgroundColor
import androidx.compose.web.css.border
import androidx.compose.web.css.color
import androidx.compose.web.css.fontSize
import androidx.compose.web.css.margin
import androidx.compose.web.css.maxWidth
import androidx.compose.web.css.media
import androidx.compose.web.css.minWidth
import androidx.compose.web.css.opacity
import androidx.compose.web.css.padding
import androidx.compose.web.css.percent
import androidx.compose.web.css.px
import androidx.compose.web.css.selectors.className
import androidx.compose.web.css.selectors.hover
import androidx.compose.web.css.selectors.plus
import androidx.compose.web.css.value
import androidx.compose.web.css.variable
import androidx.compose.web.css.width
import androidx.compose.web.elements.A
import androidx.compose.web.elements.Button
@ -32,16 +42,6 @@ import androidx.compose.web.elements.Input
import androidx.compose.web.elements.Style
import androidx.compose.web.elements.Text
import androidx.compose.web.elements.TextArea
import androidx.compose.web.css.Style
import androidx.compose.web.css.StyleSheet
import androidx.compose.web.css.and
import androidx.compose.web.css.backgroundColor
import androidx.compose.web.css.border
import androidx.compose.web.css.maxWidth
import androidx.compose.web.css.media
import androidx.compose.web.css.minWidth
import androidx.compose.web.css.value
import androidx.compose.web.css.variable
import androidx.compose.web.renderComposableInBody
import androidx.compose.web.sample.tests.launchTestCase
import kotlinx.browser.window
@ -101,13 +101,14 @@ fun CounterApp(counter: MutableState<Int>) {
Counter(counter.value)
Button(
style = {
color(if (counter.value % 2 == 0) "green" else "red")
width((counter.value + 200).px)
fontSize(if (counter.value % 2 == 0) 25.px else 30.px)
margin(15.px)
},
attrs = {
{
style {
color(if (counter.value % 2 == 0) "green" else "red")
width((counter.value + 200).px)
fontSize(if (counter.value % 2 == 0) 25.px else 30.px)
margin(15.px)
}
onClick { counter.value = counter.value + 1 }
}
) {
@ -124,9 +125,10 @@ fun Counter(value: Int) {
draggable(Draggable.True)
attr("title", "This is a counter!")
onDrag { println("DRAGGING NOW!!!!") }
},
style = {
color("red")
style {
color("red")
}
}
) {
Text("Counter = $value")
@ -208,16 +210,15 @@ fun main() {
Text("My text")
}
Div(
attrs = {
classes(
AppStyleSheet.myClass
)
},
style = {
Div({
classes(
AppStyleSheet.myClass
)
style {
opacity(0.3)
}
) {
}) {
Text("My text")
}
@ -231,9 +232,10 @@ fun main() {
}
}
)
},
style = {
opacity(30.percent)
style {
opacity(30.percent)
}
}
) {
Text("My text")
@ -252,19 +254,18 @@ fun main() {
@Composable
fun MyInputComponent(text: State<String>, onChange: (String) -> Unit) {
Div(
style = {
Div({
style {
padding(50.px)
},
attrs = {
onTouchStart {
println("On touch start")
}
onTouchEnd {
println("On touch end")
}
}
) {
onTouchStart {
println("On touch start")
}
onTouchEnd {
println("On touch end")
}
}) {
Text("Test onMouseDown")
}
@ -343,14 +344,15 @@ fun smallColoredText(text: String) {
println("DIV CREATED ${element.id}")
onDispose { println("DIV REMOVED ${element.id}") }
}
},
style = {
if (globalState.isDarkTheme) {
color("black")
} else {
color("green")
style {
if (globalState.isDarkTheme) {
color("black")
} else {
color("green")
}
}
}
},
) {
Text("Text = $text")
}

13
web/integration-core/src/jsMain/kotlin/androidx/compose/web/sample/tests/TestCases1.kt

@ -40,7 +40,7 @@ class TestCases1 {
)
Div(
attrs = {
{
id("box")
onMouseEnter {
println("Mouse enter")
@ -50,11 +50,12 @@ class TestCases1 {
println("Mouse leave")
hovered = false
}
},
style = {
width(100.px)
height(100.px)
backgroundColor("red")
style {
width(100.px)
height(100.px)
backgroundColor("red")
}
}
) {}
}

16
web/widgets/src/jsMain/kotlin/Modifier.kt

@ -16,23 +16,17 @@ actual fun Modifier.background(color: Color): Modifier = castOrCreate().apply {
}
}
fun Modifier.asStyleBuilderApplier(
passThroughHandler: (StyleBuilder.() -> Unit)? = null
): StyleBuilder.() -> Unit = castOrCreate().let { modifier ->
val st: StyleBuilder.() -> Unit = {
modifier.styleHandlers.forEach { it.invoke(this) }
passThroughHandler?.invoke(this)
}
st
}
fun Modifier.asAttributeBuilderApplier(
passThroughHandler: (AttrsBuilder<*>.() -> Unit)? = null
): AttrsBuilder<*>.() -> Unit =
castOrCreate().let { modifier ->
val st: AttrsBuilder<*>.() -> Unit = {
modifier.attrHandlers.forEach { it.invoke(this) }
style {
modifier.styleHandlers.forEach { it.invoke(this) }
}
passThroughHandler?.invoke(this)
}

2
web/widgets/src/jsMain/kotlin/layouts/box.kt

@ -1,7 +1,6 @@
package org.jetbrains.compose.common.foundation.layout
import org.jetbrains.compose.common.ui.Modifier
import org.jetbrains.compose.common.ui.asStyleBuilderApplier
import androidx.compose.runtime.Composable
import androidx.compose.web.elements.Div
import org.jetbrains.compose.common.ui.asAttributeBuilderApplier
@ -9,7 +8,6 @@ import org.jetbrains.compose.common.ui.asAttributeBuilderApplier
@Composable
internal actual fun BoxActual(modifier: Modifier, content: @Composable () -> Unit) {
Div(
style = modifier.asStyleBuilderApplier(),
attrs = modifier.asAttributeBuilderApplier()
) {
content()

2
web/widgets/src/jsMain/kotlin/layouts/button.kt

@ -3,7 +3,6 @@ package org.jetbrains.compose.common.material
import org.jetbrains.compose.common.ui.Modifier
import androidx.compose.runtime.Composable
import androidx.compose.web.elements.Button
import org.jetbrains.compose.common.ui.asStyleBuilderApplier
@Composable
actual fun ButtonActual(
@ -12,7 +11,6 @@ actual fun ButtonActual(
content: @Composable () -> Unit
) {
Button(
style = modifier.asStyleBuilderApplier(),
attrs = {
onClick { onClick() }
}

4
web/widgets/src/jsMain/kotlin/layouts/column.kt

@ -2,7 +2,6 @@ package org.jetbrains.compose.common.foundation.layout
import org.jetbrains.compose.common.ui.Modifier
import androidx.compose.runtime.Composable
import org.jetbrains.compose.common.ui.asStyleBuilderApplier
import androidx.compose.web.elements.Div
import org.jetbrains.compose.web.ui.Styles
@ -11,8 +10,7 @@ internal actual fun ColumnActual(modifier: Modifier, content: @Composable () ->
Div(
attrs = {
classes(Styles.columnClass)
},
style = modifier.asStyleBuilderApplier()
}
) {
content()
}

4
web/widgets/src/jsMain/kotlin/layouts/row.kt

@ -3,7 +3,6 @@ package org.jetbrains.compose.common.foundation.layout
import org.jetbrains.compose.common.ui.Modifier
import androidx.compose.runtime.Composable
import androidx.compose.web.elements.Div
import org.jetbrains.compose.common.ui.asStyleBuilderApplier
import org.jetbrains.compose.common.ui.Alignment
import org.jetbrains.compose.web.ui.Styles
@ -34,8 +33,7 @@ internal actual fun RowActual(
verticalAlignment.asClassName()
)
)
},
style = modifier.asStyleBuilderApplier()
}
) {
content()
}

16
web/widgets/src/jsMain/kotlin/layouts/text.kt

@ -5,7 +5,6 @@ import androidx.compose.web.elements.Text as TextNode
import androidx.compose.web.elements.Span
import org.jetbrains.compose.web.ui.Styles
import org.jetbrains.compose.common.ui.Modifier
import org.jetbrains.compose.common.ui.asStyleBuilderApplier
import org.jetbrains.compose.common.ui.asAttributeBuilderApplier
import org.jetbrains.compose.common.core.graphics.Color
import androidx.compose.web.css.color
@ -24,14 +23,15 @@ actual fun TextActual(
size: TextUnit
) {
Span(
style = modifier.asStyleBuilderApplier() {
color(RGB(color.red, color.green, color.blue))
when (size.unitType) {
TextUnitType.Em -> fontSize(size.value.em)
TextUnitType.Sp -> fontSize(size.value.px)
modifier.asAttributeBuilderApplier {
style {
color(RGB(color.red, color.green, color.blue))
when (size.unitType) {
TextUnitType.Em -> fontSize(size.value.em)
TextUnitType.Sp -> fontSize(size.value.px)
}
}
},
attrs = modifier.asAttributeBuilderApplier() {
classes(Styles.textClass)
}
) {

Loading…
Cancel
Save