Browse Source

[web] Attribute builder builds styles as well

pull/700/head
Shagen Ogandzhanian 4 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. 47
      web/core/src/jsTest/kotlin/InlineStyleTests.kt
  7. 128
      web/core/src/jsTest/kotlin/StaticComposableTests.kt
  8. 4
      web/integration-core/src/jsMain/kotlin/androidx/compose/web/sample/CodeSnippetSamples.kt
  9. 64
      web/integration-core/src/jsMain/kotlin/androidx/compose/web/sample/Sample.kt
  10. 7
      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. 8
      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.DisposableEffectResult
import androidx.compose.runtime.DisposableEffectScope import androidx.compose.runtime.DisposableEffectScope
import androidx.compose.web.css.StyleBuilder
import androidx.compose.web.css.StyleBuilderImpl
import org.w3c.dom.HTMLElement import org.w3c.dom.HTMLElement
class AttrsBuilder<TTag : Tag> : EventsListenerBuilder() { 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>>() val propertyUpdates = mutableListOf<Pair<(HTMLElement, Any) -> Unit, Any>>()
var refEffect: (DisposableEffectScope.(HTMLElement) -> DisposableEffectResult)? = null var refEffect: (DisposableEffectScope.(HTMLElement) -> DisposableEffectResult)? = null
fun style(builder: StyleBuilder.() -> Unit) {
styleBuilder.apply(builder)
}
inline fun classes(builder: ClassesAttrBuilder.() -> Unit) = inline fun classes(builder: ClassesAttrBuilder.() -> Unit) =
prop(setClassList, ClassesAttrBuilder().apply(builder).asList().toTypedArray()) prop(setClassList, ClassesAttrBuilder().apply(builder).asList().toTypedArray())
@ -30,22 +37,22 @@ class AttrsBuilder<TTag : Tag> : EventsListenerBuilder() {
} }
fun attr(attr: String, value: String?): AttrsBuilder<TTag> { fun attr(attr: String, value: String?): AttrsBuilder<TTag> {
if (value == null && attr in map) { if (value == null) {
map.remove(attr) attributesMap.remove(attr)
} else if (value != null) { } else {
map[attr] = value attributesMap[attr] = value
} }
return this return this
} }
@Suppress("UNCHECKED_CAST") @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>) propertyUpdates.add((update to value) as Pair<(HTMLElement, Any) -> Unit, Any>)
} }
fun collect(): Map<String, String> { fun collect(): Map<String, String> {
return map return attributesMap
} }
companion object { 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)) listeners.add(DragEventListener(DRAGLEAVE, options, listener))
} }
fun asList(): List<WrappedEventListener<*>> = listeners fun collectListeners(): List<WrappedEventListener<*>> = listeners
fun addEventListener( fun addEventListener(
eventName: String, 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, noinline factory: () -> T,
elementScope: TScope, elementScope: TScope,
noinline attrsSkippableUpdate: @Composable SkippableUpdater<T>.() -> Unit, noinline attrsSkippableUpdate: @Composable SkippableUpdater<T>.() -> Unit,
noinline styleSkippableUpdate: @Composable SkippableUpdater<T>.() -> Unit,
content: @Composable TScope.() -> Unit content: @Composable TScope.() -> Unit
) { ) {
if (currentComposer.applier !is E) error("Invalid applier") if (currentComposer.applier !is E) error("Invalid applier")
@ -36,11 +35,11 @@ inline fun <TScope, T, reified E : Applier<*>> ComposeDomNode(
} else { } else {
currentComposer.useNode() currentComposer.useNode()
} }
// Updater<T>(currentComposer).update()
SkippableUpdater<T>(currentComposer).apply { SkippableUpdater<T>(currentComposer).apply {
attrsSkippableUpdate() attrsSkippableUpdate()
styleSkippableUpdate()
} }
currentComposer.startReplaceableGroup(0x7ab4aae9) currentComposer.startReplaceableGroup(0x7ab4aae9)
content(elementScope) content(elementScope)
currentComposer.endReplaceableGroup() currentComposer.endReplaceableGroup()
@ -55,7 +54,6 @@ class DisposableEffectHolder(
inline fun <TTag : Tag, THTMLElement : HTMLElement> TagElement( inline fun <TTag : Tag, THTMLElement : HTMLElement> TagElement(
tagName: String, tagName: String,
crossinline applyAttrs: AttrsBuilder<TTag>.() -> Unit, crossinline applyAttrs: AttrsBuilder<TTag>.() -> Unit,
crossinline applyStyle: StyleBuilder.() -> Unit,
content: @Composable ElementScope<THTMLElement>.() -> Unit content: @Composable ElementScope<THTMLElement>.() -> Unit
) { ) {
val scope = remember { ElementScopeImpl<THTMLElement>() } val scope = remember { ElementScopeImpl<THTMLElement>() }
@ -71,18 +69,13 @@ inline fun <TTag : Tag, THTMLElement : HTMLElement> TagElement(
val attrsApplied = AttrsBuilder<TTag>().also { it.applyAttrs() } val attrsApplied = AttrsBuilder<TTag>().also { it.applyAttrs() }
refEffect.effect = attrsApplied.refEffect refEffect.effect = attrsApplied.refEffect
val attrsCollected = attrsApplied.collect() val attrsCollected = attrsApplied.collect()
val events = attrsApplied.asList() val events = attrsApplied.collectListeners()
update { update {
set(attrsCollected, DomNodeWrapper.UpdateAttrs) set(attrsCollected, DomNodeWrapper.UpdateAttrs)
set(events, DomNodeWrapper.UpdateListeners) set(events, DomNodeWrapper.UpdateListeners)
set(attrsApplied.propertyUpdates, DomNodeWrapper.UpdateProperties) set(attrsApplied.propertyUpdates, DomNodeWrapper.UpdateProperties)
} set(attrsApplied.styleBuilder, DomNodeWrapper.UpdateStyleDeclarations)
},
styleSkippableUpdate = {
val style = StyleBuilderImpl().apply(applyStyle)
update {
set(style, DomNodeWrapper.UpdateStyleDeclarations)
} }
}, },
elementScope = scope, 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.HTMLUListElement
import org.w3c.dom.Text import org.w3c.dom.Text
typealias StyleBuilderContext = StyleBuilder.() -> Unit
typealias AttrBuilderContext<T> = AttrsBuilder<T>.() -> Unit typealias AttrBuilderContext<T> = AttrsBuilder<T>.() -> Unit
typealias ContentBuilder<T> = @Composable ElementScope<T>.() -> Unit typealias ContentBuilder<T> = @Composable ElementScope<T>.() -> Unit
@ -60,13 +59,11 @@ fun Text(value: String) {
@Composable @Composable
inline fun Div( inline fun Div(
crossinline attrs: AttrBuilderContext<Tag.Div> = {}, crossinline attrs: AttrBuilderContext<Tag.Div> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLDivElement> content: ContentBuilder<HTMLDivElement>
) { ) {
TagElement( TagElement(
tagName = "div", tagName = "div",
applyAttrs = attrs, applyAttrs = attrs,
applyStyle = style,
content = content content = content
) )
} }
@ -75,7 +72,6 @@ inline fun Div(
inline fun A( inline fun A(
href: String? = null, href: String? = null,
crossinline attrs: AttrBuilderContext<Tag.A> = {}, crossinline attrs: AttrBuilderContext<Tag.A> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLAnchorElement> content: ContentBuilder<HTMLAnchorElement>
) { ) {
TagElement<Tag.A, HTMLAnchorElement>( TagElement<Tag.A, HTMLAnchorElement>(
@ -84,7 +80,6 @@ inline fun A(
href(href) href(href)
attrs() attrs()
}, },
applyStyle = style,
content = content content = content
) )
} }
@ -94,7 +89,6 @@ inline fun Input(
type: InputType = InputType.Text, type: InputType = InputType.Text,
value: String = "", value: String = "",
crossinline attrs: AttrBuilderContext<Tag.Input> = {}, crossinline attrs: AttrBuilderContext<Tag.Input> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLInputElement> = {} content: ContentBuilder<HTMLInputElement> = {}
) { ) {
TagElement<Tag.Input, HTMLInputElement>( TagElement<Tag.Input, HTMLInputElement>(
@ -104,7 +98,6 @@ inline fun Input(
value(value) value(value)
attrs() attrs()
}, },
applyStyle = style,
content = content content = content
) )
} }
@ -112,135 +105,116 @@ inline fun Input(
@Composable @Composable
inline fun Button( inline fun Button(
crossinline attrs: AttrBuilderContext<Tag.Button> = {}, crossinline attrs: AttrBuilderContext<Tag.Button> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLHeadingElement> content: ContentBuilder<HTMLHeadingElement>
) = TagElement("button", applyAttrs = attrs, applyStyle = style, content = content) ) = TagElement("button", applyAttrs = attrs, content = content)
@Composable @Composable
inline fun H1( inline fun H1(
crossinline attrs: AttrBuilderContext<Tag.H> = {}, crossinline attrs: AttrBuilderContext<Tag.H> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLHeadingElement> content: ContentBuilder<HTMLHeadingElement>
) = TagElement("h1", applyAttrs = attrs, applyStyle = style, content = content) ) = TagElement("h1", applyAttrs = attrs, content = content)
@Composable @Composable
inline fun H2( inline fun H2(
crossinline attrs: AttrBuilderContext<Tag.H> = {}, crossinline attrs: AttrBuilderContext<Tag.H> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLHeadingElement> content: ContentBuilder<HTMLHeadingElement>
) = TagElement("h2", applyAttrs = attrs, applyStyle = style, content = content) ) = TagElement("h2", applyAttrs = attrs, content = content)
@Composable @Composable
inline fun H3( inline fun H3(
crossinline attrs: AttrBuilderContext<Tag.H> = {}, crossinline attrs: AttrBuilderContext<Tag.H> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLHeadingElement> content: ContentBuilder<HTMLHeadingElement>
) = TagElement("h3", applyAttrs = attrs, applyStyle = style, content = content) ) = TagElement("h3", applyAttrs = attrs, content = content)
@Composable @Composable
inline fun H4( inline fun H4(
crossinline attrs: AttrBuilderContext<Tag.H> = {}, crossinline attrs: AttrBuilderContext<Tag.H> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLHeadingElement> content: ContentBuilder<HTMLHeadingElement>
) = TagElement("h4", applyAttrs = attrs, applyStyle = style, content = content) ) = TagElement("h4", applyAttrs = attrs, content = content)
@Composable @Composable
inline fun H5( inline fun H5(
crossinline attrs: AttrBuilderContext<Tag.H> = {}, crossinline attrs: AttrBuilderContext<Tag.H> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLHeadingElement> content: ContentBuilder<HTMLHeadingElement>
) = TagElement("h5", applyAttrs = attrs, applyStyle = style, content = content) ) = TagElement("h5", applyAttrs = attrs, content = content)
@Composable @Composable
inline fun H6( inline fun H6(
crossinline attrs: AttrBuilderContext<Tag.H> = {}, crossinline attrs: AttrBuilderContext<Tag.H> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLHeadingElement> content: ContentBuilder<HTMLHeadingElement>
) = TagElement("h6", applyAttrs = attrs, applyStyle = style, content = content) ) = TagElement("h6", applyAttrs = attrs, content = content)
@Composable @Composable
inline fun P( inline fun P(
crossinline attrs: AttrBuilderContext<Tag.P> = {}, crossinline attrs: AttrBuilderContext<Tag.P> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLParagraphElement> content: ContentBuilder<HTMLParagraphElement>
) = TagElement("p", applyAttrs = attrs, applyStyle = style, content = content) ) = TagElement("p", applyAttrs = attrs, content = content)
@Composable @Composable
inline fun Em( inline fun Em(
crossinline attrs: AttrBuilderContext<Tag> = {}, crossinline attrs: AttrBuilderContext<Tag> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLElement> content: ContentBuilder<HTMLElement>
) = TagElement("em", applyAttrs = attrs, applyStyle = style, content = content) ) = TagElement("em", applyAttrs = attrs, content = content)
@Composable @Composable
inline fun I( inline fun I(
crossinline attrs: AttrBuilderContext<Tag> = {}, crossinline attrs: AttrBuilderContext<Tag> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLElement> content: ContentBuilder<HTMLElement>
) = TagElement("i", applyAttrs = attrs, applyStyle = style, content = content) ) = TagElement("i", applyAttrs = attrs, content = content)
@Composable @Composable
inline fun B( inline fun B(
crossinline attrs: AttrBuilderContext<Tag> = {}, crossinline attrs: AttrBuilderContext<Tag> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLElement> content: ContentBuilder<HTMLElement>
) = TagElement("b", applyAttrs = attrs, applyStyle = style, content = content) ) = TagElement("b", applyAttrs = attrs, content = content)
@Composable @Composable
inline fun Small( inline fun Small(
crossinline attrs: AttrBuilderContext<Tag> = {}, crossinline attrs: AttrBuilderContext<Tag> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLElement> content: ContentBuilder<HTMLElement>
) = TagElement("small", applyAttrs = attrs, applyStyle = style, content = content) ) = TagElement("small", applyAttrs = attrs, content = content)
@Composable @Composable
inline fun Span( inline fun Span(
crossinline attrs: AttrBuilderContext<Tag.Span> = {}, crossinline attrs: AttrBuilderContext<Tag.Span> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLSpanElement> content: ContentBuilder<HTMLSpanElement>
) = TagElement("span", applyAttrs = attrs, applyStyle = style, content = content) ) = TagElement("span", applyAttrs = attrs, content = content)
@Composable @Composable
inline fun Br( inline fun Br(
crossinline attrs: AttrBuilderContext<Tag.Br> = {}, crossinline attrs: AttrBuilderContext<Tag.Br> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLBRElement> content: ContentBuilder<HTMLBRElement>
) = TagElement("br", applyAttrs = attrs, applyStyle = style, content = content) ) = TagElement("br", applyAttrs = attrs, content = content)
@Composable @Composable
inline fun Ul( inline fun Ul(
crossinline attrs: AttrBuilderContext<Tag.Ul> = {}, crossinline attrs: AttrBuilderContext<Tag.Ul> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLUListElement>, content: ContentBuilder<HTMLUListElement>,
) = TagElement("ul", applyAttrs = attrs, applyStyle = style, content = content) ) = TagElement("ul", applyAttrs = attrs, content = content)
@Composable @Composable
inline fun Ol( inline fun Ol(
crossinline attrs: AttrBuilderContext<Tag.Ol> = {}, crossinline attrs: AttrBuilderContext<Tag.Ol> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLOListElement> content: ContentBuilder<HTMLOListElement>
) = TagElement("ol", applyAttrs = attrs, applyStyle = style, content = content) ) = TagElement("ol", applyAttrs = attrs, content = content)
@Composable @Composable
inline fun DOMScope<HTMLOListElement>.Li( inline fun DOMScope<HTMLOListElement>.Li(
crossinline attrs: AttrBuilderContext<Tag.Li> = {}, crossinline attrs: AttrBuilderContext<Tag.Li> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLLIElement> content: ContentBuilder<HTMLLIElement>
) = TagElement("li", applyAttrs = attrs, applyStyle = style, content = content) ) = TagElement("li", applyAttrs = attrs, content = content)
@Composable @Composable
inline fun DOMScope<HTMLUListElement>.Li( inline fun DOMScope<HTMLUListElement>.Li(
crossinline attrs: AttrBuilderContext<Tag.Li> = {}, crossinline attrs: AttrBuilderContext<Tag.Li> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLLIElement> content: ContentBuilder<HTMLLIElement>
) = TagElement("li", applyAttrs = attrs, applyStyle = style, content = content) ) = TagElement("li", applyAttrs = attrs, content = content)
@Composable @Composable
inline fun Img( inline fun Img(
src: String, src: String,
alt: String = "", alt: String = "",
crossinline attrs: AttrBuilderContext<Tag.Img> = {}, crossinline attrs: AttrBuilderContext<Tag.Img> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLImageElement> = {} content: ContentBuilder<HTMLImageElement> = {}
) = TagElement<Tag.Img, HTMLImageElement>( ) = TagElement<Tag.Img, HTMLImageElement>(
tagName = "img", tagName = "img",
@ -248,14 +222,13 @@ inline fun Img(
src(src).alt(alt) src(src).alt(alt)
attrs() attrs()
}, },
applyStyle = style, content = content content = content
) )
@Composable @Composable
inline fun Form( inline fun Form(
action: String? = null, action: String? = null,
crossinline attrs: AttrBuilderContext<Tag.Form> = {}, crossinline attrs: AttrBuilderContext<Tag.Form> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLFormElement> content: ContentBuilder<HTMLFormElement>
) = TagElement<Tag.Form, HTMLFormElement>( ) = TagElement<Tag.Form, HTMLFormElement>(
tagName = "form", tagName = "form",
@ -263,18 +236,16 @@ inline fun Form(
if (!action.isNullOrEmpty()) action(action) if (!action.isNullOrEmpty()) action(action)
attrs() attrs()
}, },
applyStyle = style, content = content content = content
) )
@Composable @Composable
inline fun Select( inline fun Select(
crossinline attrs: AttrBuilderContext<Tag.Select> = {}, crossinline attrs: AttrBuilderContext<Tag.Select> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLSelectElement> content: ContentBuilder<HTMLSelectElement>
) = TagElement( ) = TagElement(
tagName = "select", tagName = "select",
applyAttrs = attrs, applyAttrs = attrs,
applyStyle = style,
content = content content = content
) )
@ -282,7 +253,6 @@ inline fun Select(
inline fun DOMScope<HTMLUListElement>.Option( inline fun DOMScope<HTMLUListElement>.Option(
value: String, value: String,
crossinline attrs: AttrBuilderContext<Tag.Option> = {}, crossinline attrs: AttrBuilderContext<Tag.Option> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLOptionElement> content: ContentBuilder<HTMLOptionElement>
) = TagElement<Tag.Option, HTMLOptionElement>( ) = TagElement<Tag.Option, HTMLOptionElement>(
tagName = "option", tagName = "option",
@ -290,7 +260,6 @@ inline fun DOMScope<HTMLUListElement>.Option(
value(value) value(value)
attrs() attrs()
}, },
applyStyle = style,
content = content content = content
) )
@ -298,7 +267,6 @@ inline fun DOMScope<HTMLUListElement>.Option(
inline fun OptGroup( inline fun OptGroup(
label: String, label: String,
crossinline attrs: AttrBuilderContext<Tag.OptGroup> = {}, crossinline attrs: AttrBuilderContext<Tag.OptGroup> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLOptGroupElement> content: ContentBuilder<HTMLOptGroupElement>
) = TagElement<Tag.OptGroup, HTMLOptGroupElement>( ) = TagElement<Tag.OptGroup, HTMLOptGroupElement>(
tagName = "optgroup", tagName = "optgroup",
@ -306,34 +274,29 @@ inline fun OptGroup(
label(label) label(label)
attrs() attrs()
}, },
applyStyle = style,
content = content content = content
) )
@Composable @Composable
inline fun Section( inline fun Section(
crossinline attrs: AttrBuilderContext<Tag> = {}, crossinline attrs: AttrBuilderContext<Tag> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLElement> content: ContentBuilder<HTMLElement>
) = TagElement( ) = TagElement(
tagName = "section", tagName = "section",
applyAttrs = attrs, applyAttrs = attrs,
applyStyle = style,
content = content content = content
) )
@Composable @Composable
inline fun TextArea( inline fun TextArea(
crossinline attrs: AttrBuilderContext<Tag.TextArea> = {}, crossinline attrs: AttrBuilderContext<Tag.TextArea> = {},
crossinline style: StyleBuilderContext = {},
value: String value: String
) = TagElement<Tag.TextArea, HTMLTextAreaElement>( ) = TagElement<Tag.TextArea, HTMLTextAreaElement>(
tagName = "textarea", tagName = "textarea",
applyAttrs = { applyAttrs = {
value(value) value(value)
attrs() attrs()
}, }
applyStyle = style
) { ) {
Text(value) Text(value)
} }
@ -341,25 +304,21 @@ inline fun TextArea(
@Composable @Composable
inline fun Nav( inline fun Nav(
crossinline attrs: AttrBuilderContext<Tag.Nav> = {}, crossinline attrs: AttrBuilderContext<Tag.Nav> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLElement> content: ContentBuilder<HTMLElement>
) = TagElement( ) = TagElement(
tagName = "nav", tagName = "nav",
applyAttrs = attrs, applyAttrs = attrs,
applyStyle = style,
content = content content = content
) )
@Composable @Composable
inline fun Pre( inline fun Pre(
crossinline attrs: AttrBuilderContext<Tag.Pre> = {}, crossinline attrs: AttrBuilderContext<Tag.Pre> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLPreElement> content: ContentBuilder<HTMLPreElement>
) { ) {
TagElement( TagElement(
tagName = "pre", tagName = "pre",
applyAttrs = attrs, applyAttrs = attrs,
applyStyle = style,
content = content content = content
) )
} }
@ -367,13 +326,11 @@ inline fun Pre(
@Composable @Composable
inline fun Code( inline fun Code(
crossinline attrs: AttrBuilderContext<Tag.Code> = {}, crossinline attrs: AttrBuilderContext<Tag.Code> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLElement> content: ContentBuilder<HTMLElement>
) { ) {
TagElement( TagElement(
tagName = "code", tagName = "code",
applyAttrs = attrs, applyAttrs = attrs,
applyStyle = style,
content = content content = content
) )
} }
@ -381,13 +338,11 @@ inline fun Code(
@Composable @Composable
inline fun Main( inline fun Main(
crossinline attrs: AttrBuilderContext<Tag.Div> = {}, crossinline attrs: AttrBuilderContext<Tag.Div> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLElement> = {} content: ContentBuilder<HTMLElement> = {}
) { ) {
TagElement<Tag.Div, HTMLAnchorElement>( TagElement<Tag.Div, HTMLAnchorElement>(
tagName = "main", tagName = "main",
applyAttrs = attrs, applyAttrs = attrs,
applyStyle = style,
content = content content = content
) )
} }
@ -395,13 +350,11 @@ inline fun Main(
@Composable @Composable
inline fun Footer( inline fun Footer(
crossinline attrs: AttrBuilderContext<Tag.Div> = {}, crossinline attrs: AttrBuilderContext<Tag.Div> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLElement> = {} content: ContentBuilder<HTMLElement> = {}
) { ) {
TagElement<Tag.Div, HTMLAnchorElement>( TagElement<Tag.Div, HTMLAnchorElement>(
tagName = "footer", tagName = "footer",
applyAttrs = attrs, applyAttrs = attrs,
applyStyle = style,
content = content content = content
) )
} }
@ -410,7 +363,6 @@ inline fun Footer(
inline fun Label( inline fun Label(
forId: String? = null, forId: String? = null,
crossinline attrs: AttrBuilderContext<Tag.Label> = {}, crossinline attrs: AttrBuilderContext<Tag.Label> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLElement> = {} content: ContentBuilder<HTMLElement> = {}
) { ) {
TagElement<Tag.Label, HTMLAnchorElement>( TagElement<Tag.Label, HTMLAnchorElement>(
@ -419,7 +371,6 @@ inline fun Label(
forId(forId) forId(forId)
attrs() attrs()
}, },
applyStyle = style,
content = content content = content
) )
} }
@ -427,13 +378,11 @@ inline fun Label(
@Composable @Composable
inline fun Table( inline fun Table(
crossinline attrs: AttrBuilderContext<Tag.Table> = {}, crossinline attrs: AttrBuilderContext<Tag.Table> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLTableElement> content: ContentBuilder<HTMLTableElement>
) { ) {
TagElement( TagElement(
tagName = "table", tagName = "table",
applyAttrs = attrs, applyAttrs = attrs,
applyStyle = style,
content = content content = content
) )
} }
@ -441,13 +390,11 @@ inline fun Table(
@Composable @Composable
inline fun Caption( inline fun Caption(
crossinline attrs: AttrBuilderContext<Tag.Caption> = {}, crossinline attrs: AttrBuilderContext<Tag.Caption> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLTableCaptionElement> content: ContentBuilder<HTMLTableCaptionElement>
) { ) {
TagElement( TagElement(
tagName = "caption", tagName = "caption",
applyAttrs = attrs, applyAttrs = attrs,
applyStyle = style,
content = content content = content
) )
} }
@ -455,13 +402,11 @@ inline fun Caption(
@Composable @Composable
inline fun Col( inline fun Col(
crossinline attrs: AttrBuilderContext<Tag.Col> = {}, crossinline attrs: AttrBuilderContext<Tag.Col> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLTableColElement> content: ContentBuilder<HTMLTableColElement>
) { ) {
TagElement( TagElement(
tagName = "col", tagName = "col",
applyAttrs = attrs, applyAttrs = attrs,
applyStyle = style,
content = content content = content
) )
} }
@ -469,13 +414,11 @@ inline fun Col(
@Composable @Composable
inline fun Colgroup( inline fun Colgroup(
crossinline attrs: AttrBuilderContext<Tag.Colgroup> = {}, crossinline attrs: AttrBuilderContext<Tag.Colgroup> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLTableColElement> content: ContentBuilder<HTMLTableColElement>
) { ) {
TagElement( TagElement(
tagName = "colgroup", tagName = "colgroup",
applyAttrs = attrs, applyAttrs = attrs,
applyStyle = style,
content = content content = content
) )
} }
@ -483,13 +426,11 @@ inline fun Colgroup(
@Composable @Composable
inline fun Tr( inline fun Tr(
crossinline attrs: AttrBuilderContext<Tag.Tr> = {}, crossinline attrs: AttrBuilderContext<Tag.Tr> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLTableRowElement> content: ContentBuilder<HTMLTableRowElement>
) { ) {
TagElement( TagElement(
tagName = "tr", tagName = "tr",
applyAttrs = attrs, applyAttrs = attrs,
applyStyle = style,
content = content content = content
) )
} }
@ -497,13 +438,11 @@ inline fun Tr(
@Composable @Composable
inline fun Thead( inline fun Thead(
crossinline attrs: AttrBuilderContext<Tag.Thead> = {}, crossinline attrs: AttrBuilderContext<Tag.Thead> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLTableSectionElement> content: ContentBuilder<HTMLTableSectionElement>
) { ) {
TagElement( TagElement(
tagName = "thead", tagName = "thead",
applyAttrs = attrs, applyAttrs = attrs,
applyStyle = style,
content = content content = content
) )
} }
@ -511,13 +450,11 @@ inline fun Thead(
@Composable @Composable
inline fun Th( inline fun Th(
crossinline attrs: AttrBuilderContext<Tag.Th> = {}, crossinline attrs: AttrBuilderContext<Tag.Th> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLTableCellElement> content: ContentBuilder<HTMLTableCellElement>
) { ) {
TagElement( TagElement(
tagName = "th", tagName = "th",
applyAttrs = attrs, applyAttrs = attrs,
applyStyle = style,
content = content content = content
) )
} }
@ -525,13 +462,11 @@ inline fun Th(
@Composable @Composable
inline fun Td( inline fun Td(
crossinline attrs: AttrBuilderContext<Tag.Td> = {}, crossinline attrs: AttrBuilderContext<Tag.Td> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLTableCellElement> content: ContentBuilder<HTMLTableCellElement>
) { ) {
TagElement( TagElement(
tagName = "td", tagName = "td",
applyAttrs = attrs, applyAttrs = attrs,
applyStyle = style,
content = content content = content
) )
} }
@ -539,13 +474,11 @@ inline fun Td(
@Composable @Composable
inline fun Tbody( inline fun Tbody(
crossinline attrs: AttrBuilderContext<Tag.Tbody> = {}, crossinline attrs: AttrBuilderContext<Tag.Tbody> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLTableSectionElement> content: ContentBuilder<HTMLTableSectionElement>
) { ) {
TagElement( TagElement(
tagName = "tbody", tagName = "tbody",
applyAttrs = attrs, applyAttrs = attrs,
applyStyle = style,
content = content content = content
) )
} }
@ -553,13 +486,11 @@ inline fun Tbody(
@Composable @Composable
inline fun Tfoot( inline fun Tfoot(
crossinline attrs: AttrBuilderContext<Tag.Tfoot> = {}, crossinline attrs: AttrBuilderContext<Tag.Tfoot> = {},
crossinline style: StyleBuilderContext = {},
content: ContentBuilder<HTMLTableSectionElement> content: ContentBuilder<HTMLTableSectionElement>
) { ) {
TagElement( TagElement(
tagName = "tfoot", tagName = "tfoot",
applyAttrs = attrs, applyAttrs = attrs,
applyStyle = style,
content = content content = content
) )
} }

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

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

47
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.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue 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.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.Span
import androidx.compose.web.elements.Text import androidx.compose.web.elements.Text
import kotlin.test.Test import kotlin.test.Test
@ -15,13 +21,15 @@ class InlineStyleTests {
var isRed by mutableStateOf(true) var isRed by mutableStateOf(true)
composition { composition {
Span( Span(
style = { {
style {
if (isRed) { if (isRed) {
color("red") color("red")
} else { } else {
color("green") color("green")
} }
} }
}
) { ) {
Text("text") Text("text")
} }
@ -46,11 +54,13 @@ class InlineStyleTests {
var isRed by mutableStateOf(false) var isRed by mutableStateOf(false)
composition { composition {
Span( Span(
style = { {
style {
if (isRed) { if (isRed) {
color("red") color("red")
} }
} }
}
) { ) {
Text("text") Text("text")
} }
@ -75,11 +85,13 @@ class InlineStyleTests {
var isRed by mutableStateOf(true) var isRed by mutableStateOf(true)
composition { composition {
Span( Span(
style = { {
style {
if (isRed) { if (isRed) {
color("red") color("red")
} }
} }
}
) { ) {
Text("text") Text("text")
} }
@ -104,11 +116,13 @@ class InlineStyleTests {
var isRed by mutableStateOf(true) var isRed by mutableStateOf(true)
composition { composition {
Span( Span(
style = { {
style {
if (isRed) { if (isRed) {
color("red") color("red")
} }
} }
}
) { ) {
Text("text") Text("text")
} }
@ -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
)
}
} }

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

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

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

@ -20,9 +20,11 @@ fun KotlinCodeSnippets() {
val currentSnippet = remember { mutableStateOf("") } val currentSnippet = remember { mutableStateOf("") }
Div( Div(
style = { {
style {
padding(5.px) padding(5.px)
} }
}
) { ) {
H4 { H4 {
Text("Choose code snippet:") Text("Choose code snippet:")

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

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

@ -40,7 +40,7 @@ class TestCases1 {
) )
Div( Div(
attrs = { {
id("box") id("box")
onMouseEnter { onMouseEnter {
println("Mouse enter") println("Mouse enter")
@ -50,12 +50,13 @@ class TestCases1 {
println("Mouse leave") println("Mouse leave")
hovered = false hovered = false
} }
},
style = { style {
width(100.px) width(100.px)
height(100.px) height(100.px)
backgroundColor("red") 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( fun Modifier.asAttributeBuilderApplier(
passThroughHandler: (AttrsBuilder<*>.() -> Unit)? = null passThroughHandler: (AttrsBuilder<*>.() -> Unit)? = null
): AttrsBuilder<*>.() -> Unit = ): AttrsBuilder<*>.() -> Unit =
castOrCreate().let { modifier -> castOrCreate().let { modifier ->
val st: AttrsBuilder<*>.() -> Unit = { val st: AttrsBuilder<*>.() -> Unit = {
modifier.attrHandlers.forEach { it.invoke(this) } modifier.attrHandlers.forEach { it.invoke(this) }
style {
modifier.styleHandlers.forEach { it.invoke(this) }
}
passThroughHandler?.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 package org.jetbrains.compose.common.foundation.layout
import org.jetbrains.compose.common.ui.Modifier import org.jetbrains.compose.common.ui.Modifier
import org.jetbrains.compose.common.ui.asStyleBuilderApplier
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.web.elements.Div import androidx.compose.web.elements.Div
import org.jetbrains.compose.common.ui.asAttributeBuilderApplier import org.jetbrains.compose.common.ui.asAttributeBuilderApplier
@ -9,7 +8,6 @@ import org.jetbrains.compose.common.ui.asAttributeBuilderApplier
@Composable @Composable
internal actual fun BoxActual(modifier: Modifier, content: @Composable () -> Unit) { internal actual fun BoxActual(modifier: Modifier, content: @Composable () -> Unit) {
Div( Div(
style = modifier.asStyleBuilderApplier(),
attrs = modifier.asAttributeBuilderApplier() attrs = modifier.asAttributeBuilderApplier()
) { ) {
content() 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 org.jetbrains.compose.common.ui.Modifier
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.web.elements.Button import androidx.compose.web.elements.Button
import org.jetbrains.compose.common.ui.asStyleBuilderApplier
@Composable @Composable
actual fun ButtonActual( actual fun ButtonActual(
@ -12,7 +11,6 @@ actual fun ButtonActual(
content: @Composable () -> Unit content: @Composable () -> Unit
) { ) {
Button( Button(
style = modifier.asStyleBuilderApplier(),
attrs = { attrs = {
onClick { onClick() } 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 org.jetbrains.compose.common.ui.Modifier
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import org.jetbrains.compose.common.ui.asStyleBuilderApplier
import androidx.compose.web.elements.Div import androidx.compose.web.elements.Div
import org.jetbrains.compose.web.ui.Styles import org.jetbrains.compose.web.ui.Styles
@ -11,8 +10,7 @@ internal actual fun ColumnActual(modifier: Modifier, content: @Composable () ->
Div( Div(
attrs = { attrs = {
classes(Styles.columnClass) classes(Styles.columnClass)
}, }
style = modifier.asStyleBuilderApplier()
) { ) {
content() 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 org.jetbrains.compose.common.ui.Modifier
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.web.elements.Div import androidx.compose.web.elements.Div
import org.jetbrains.compose.common.ui.asStyleBuilderApplier
import org.jetbrains.compose.common.ui.Alignment import org.jetbrains.compose.common.ui.Alignment
import org.jetbrains.compose.web.ui.Styles import org.jetbrains.compose.web.ui.Styles
@ -34,8 +33,7 @@ internal actual fun RowActual(
verticalAlignment.asClassName() verticalAlignment.asClassName()
) )
) )
}, }
style = modifier.asStyleBuilderApplier()
) { ) {
content() content()
} }

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

Loading…
Cancel
Save