Browse Source

web: hide internal properties from AttrsScope, EventsListenerScope, StyleScope (#1802)

Co-authored-by: Oleksandr Karpovich <oleksandr.karpovich@jetbrains.com>
web_reuse_attrsScope_instance
Oleksandr Karpovich 2 years ago committed by GitHub
parent
commit
7ea30be924
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 53
      web/core/src/jsMain/kotlin/org/jetbrains/compose/web/attributes/AttrsScope.kt
  2. 136
      web/core/src/jsMain/kotlin/org/jetbrains/compose/web/attributes/EventsListenerScope.kt
  3. 5
      web/core/src/jsMain/kotlin/org/jetbrains/compose/web/attributes/builders/InputAttrsScope.kt
  4. 4
      web/core/src/jsMain/kotlin/org/jetbrains/compose/web/attributes/builders/SelectAttrsScope.kt
  5. 2
      web/core/src/jsMain/kotlin/org/jetbrains/compose/web/attributes/builders/TextAreaAttrsScope.kt
  6. 21
      web/core/src/jsMain/kotlin/org/jetbrains/compose/web/css/StyleScope.kt
  7. 5
      web/core/src/jsMain/kotlin/org/jetbrains/compose/web/elements/Base.kt
  8. 14
      web/core/src/jsMain/kotlin/org/jetbrains/compose/web/elements/Elements.kt
  9. 7
      web/core/src/jsTest/kotlin/elements/AttributesTests.kt
  10. 1
      web/settings.gradle.kts

53
web/core/src/jsMain/kotlin/org/jetbrains/compose/web/attributes/AttrsScope.kt

@ -28,16 +28,6 @@ typealias AttrsBuilder<T> = AttrsScopeBuilder<T>
* *
*/ */
interface AttrsScope<TElement : Element>: EventsListenerScope { interface AttrsScope<TElement : Element>: EventsListenerScope {
@ComposeWebInternalApi
val attributesMap: Map<String, String>
@ComposeWebInternalApi
val styleScope: StyleScope
@ComposeWebInternalApi
val propertyUpdates: List<Pair<(Element, Any) -> Unit, Any>>
@ComposeWebInternalApi
var refEffect: (DisposableEffectScope.(TElement) -> DisposableEffectResult)?
/** /**
* [style] add inline CSS-style properties to the element via [StyleScope] context * [style] add inline CSS-style properties to the element via [StyleScope] context
* *
@ -50,9 +40,7 @@ interface AttrsScope<TElement : Element>: EventsListenerScope {
* *
* `attr("style", ...)` overrides everything added in `style { }` blocks * `attr("style", ...)` overrides everything added in `style { }` blocks
*/ */
fun style(builder: StyleScope.() -> Unit) { fun style(builder: StyleScope.() -> Unit)
styleScope.apply(builder)
}
/** /**
* [classes] adds all values passed as params to the element's classList. * [classes] adds all values passed as params to the element's classList.
@ -105,7 +93,7 @@ interface AttrsScope<TElement : Element>: EventsListenerScope {
fun attr(attr: String, value: String): AttrsScope<TElement> fun attr(attr: String, value: String): AttrsScope<TElement>
/** /**
* [prop] allows setting values of element's properties which can't be set by ussing [attr]. * [prop] allows setting values of element's properties which can't be set using [attr].
* [update] is a lambda with two parameters: `element` and `value`. `element` is a reference to a native element. * [update] is a lambda with two parameters: `element` and `value`. `element` is a reference to a native element.
* Some examples of properties that can set using [prop]: `value`, `checked`, `innerText`. * Some examples of properties that can set using [prop]: `value`, `checked`, `innerText`.
* *
@ -124,9 +112,6 @@ interface AttrsScope<TElement : Element>: EventsListenerScope {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
fun <E : HTMLElement, V> prop(update: (E, V) -> Unit, value: V) fun <E : HTMLElement, V> prop(update: (E, V) -> Unit, value: V)
@ComposeWebInternalApi
fun copyFrom(attrsScope: AttrsScope<TElement>)
companion object { companion object {
const val CLASS = "class" const val CLASS = "class"
const val ID = "id" const val ID = "id"
@ -141,13 +126,13 @@ interface AttrsScope<TElement : Element>: EventsListenerScope {
} }
} }
open class AttrsScopeBuilder<TElement : Element> : AttrsScope<TElement>, EventsListenerScope by EventsListenerScopeBuilder() { open class AttrsScopeBuilder<TElement : Element>(
override val attributesMap = mutableMapOf<String, String>() internal val eventsListenerScopeBuilder: EventsListenerScopeBuilder = EventsListenerScopeBuilder()
override val styleScope: StyleScope = StyleScopeBuilder() ) : AttrsScope<TElement>, EventsListenerScope by eventsListenerScopeBuilder {
internal val attributesMap = mutableMapOf<String, String>()
override val propertyUpdates = mutableListOf<Pair<(Element, Any) -> Unit, Any>>() internal val styleScope: StyleScopeBuilder = StyleScopeBuilder()
override var refEffect: (DisposableEffectScope.(TElement) -> DisposableEffectResult)? = null internal val propertyUpdates = mutableListOf<Pair<(Element, Any) -> Unit, Any>>()
internal var refEffect: (DisposableEffectScope.(TElement) -> DisposableEffectResult)? = null
internal val classes: MutableList<String> = mutableListOf() internal val classes: MutableList<String> = mutableListOf()
/** /**
@ -160,6 +145,22 @@ open class AttrsScopeBuilder<TElement : Element> : AttrsScope<TElement>, EventsL
this.classes.addAll(classes) this.classes.addAll(classes)
} }
/**
* [style] add inline CSS-style properties to the element via [StyleScope] context
*
* Example:
* ```
* Div({
* style { maxWidth(5.px) }
* })
* ```
*
* `attr("style", ...)` overrides everything added in `style { }` blocks
*/
override fun style(builder: StyleScope.() -> Unit) {
styleScope.apply(builder)
}
/** /**
* [ref] can be used to retrieve a reference to a html element. * [ref] can be used to retrieve a reference to a html element.
* The lambda that `ref` takes in is not Composable. It will be called only once when an element added into a composition. * The lambda that `ref` takes in is not Composable. It will be called only once when an element added into a composition.
@ -212,14 +213,14 @@ open class AttrsScopeBuilder<TElement : Element> : AttrsScope<TElement>, EventsL
} }
@ComposeWebInternalApi @ComposeWebInternalApi
override fun copyFrom(attrsScope: AttrsScope<TElement>) { internal fun copyFrom(attrsScope: AttrsScopeBuilder<TElement>) {
refEffect = attrsScope.refEffect refEffect = attrsScope.refEffect
styleScope.copyFrom(attrsScope.styleScope) styleScope.copyFrom(attrsScope.styleScope)
attributesMap.putAll(attrsScope.attributesMap) attributesMap.putAll(attrsScope.attributesMap)
propertyUpdates.addAll(attrsScope.propertyUpdates) propertyUpdates.addAll(attrsScope.propertyUpdates)
copyListenersFrom(attrsScope) eventsListenerScopeBuilder.copyListenersFrom(attrsScope.eventsListenerScopeBuilder)
} }
} }

136
web/core/src/jsMain/kotlin/org/jetbrains/compose/web/attributes/EventsListenerScope.kt

@ -25,180 +25,175 @@ typealias EventsListenerBuilder = EventsListenerScopeBuilder
* use [addEventListener] * use [addEventListener]
*/ */
interface EventsListenerScope { interface EventsListenerScope {
@ComposeWebInternalApi
val listeners: List<SyntheticEventListener<*>>
@ComposeWebInternalApi @ComposeWebInternalApi
fun registerEventListener(listener: SyntheticEventListener<*>) fun registerEventListener(listener: SyntheticEventListener<*>)
/* Mouse Events */ /* Mouse Events */
fun onContextMenu(listener: SyntheticMouseEventListener) { fun onContextMenu(listener: SyntheticMouseEventListener) {
registerEventListener(MouseEventListener(CONTEXTMENU, listener)) registerEventListener(MouseEventListener(CONTEXTMENU, listener))
} }
fun onClick(listener: SyntheticMouseEventListener) { fun onClick(listener: SyntheticMouseEventListener) {
registerEventListener(MouseEventListener(CLICK, listener)) registerEventListener(MouseEventListener(CLICK, listener))
} }
fun onDoubleClick(listener: SyntheticMouseEventListener) { fun onDoubleClick(listener: SyntheticMouseEventListener) {
registerEventListener(MouseEventListener(DBLCLICK, listener)) registerEventListener(MouseEventListener(DBLCLICK, listener))
} }
fun onMouseDown(listener: SyntheticMouseEventListener) { fun onMouseDown(listener: SyntheticMouseEventListener) {
registerEventListener(MouseEventListener(MOUSEDOWN, listener)) registerEventListener(MouseEventListener(MOUSEDOWN, listener))
} }
fun onMouseUp(listener: SyntheticMouseEventListener) { fun onMouseUp(listener: SyntheticMouseEventListener) {
registerEventListener(MouseEventListener(MOUSEUP, listener)) registerEventListener(MouseEventListener(MOUSEUP, listener))
} }
fun onMouseEnter(listener: SyntheticMouseEventListener) { fun onMouseEnter(listener: SyntheticMouseEventListener) {
registerEventListener(MouseEventListener(MOUSEENTER, listener)) registerEventListener(MouseEventListener(MOUSEENTER, listener))
} }
fun onMouseLeave(listener: SyntheticMouseEventListener) { fun onMouseLeave(listener: SyntheticMouseEventListener) {
registerEventListener(MouseEventListener(MOUSELEAVE, listener)) registerEventListener(MouseEventListener(MOUSELEAVE, listener))
} }
fun onMouseMove(listener: SyntheticMouseEventListener) { fun onMouseMove(listener: SyntheticMouseEventListener) {
registerEventListener(MouseEventListener(MOUSEMOVE, listener)) registerEventListener(MouseEventListener(MOUSEMOVE, listener))
} }
fun onMouseOut(listener: SyntheticMouseEventListener) { fun onMouseOut(listener: SyntheticMouseEventListener) {
registerEventListener(MouseEventListener(MOUSEOUT, listener)) registerEventListener(MouseEventListener(MOUSEOUT, listener))
} }
fun onMouseOver(listener: SyntheticMouseEventListener) { fun onMouseOver(listener: SyntheticMouseEventListener) {
registerEventListener(MouseEventListener(MOUSEOVER, listener)) registerEventListener(MouseEventListener(MOUSEOVER, listener))
} }
fun onWheel(listener: SyntheticWheelEventListener) { fun onWheel(listener: SyntheticWheelEventListener) {
registerEventListener(MouseWheelEventListener(WHEEL, listener)) registerEventListener(MouseWheelEventListener(WHEEL, listener))
} }
/* Drag Events */ /* Drag Events */
fun onDrag(listener: SyntheticDragEventListener) { fun onDrag(listener: SyntheticDragEventListener) {
registerEventListener(DragEventListener(DRAG, listener)) registerEventListener(DragEventListener(DRAG, listener))
} }
fun onDrop(listener: SyntheticDragEventListener) { fun onDrop(listener: SyntheticDragEventListener) {
registerEventListener(DragEventListener(DROP, listener)) registerEventListener(DragEventListener(DROP, listener))
} }
fun onDragStart(listener: SyntheticDragEventListener) { fun onDragStart(listener: SyntheticDragEventListener) {
registerEventListener(DragEventListener(DRAGSTART, listener)) registerEventListener(DragEventListener(DRAGSTART, listener))
} }
fun onDragEnd(listener: SyntheticDragEventListener) { fun onDragEnd(listener: SyntheticDragEventListener) {
registerEventListener(DragEventListener(DRAGEND, listener)) registerEventListener(DragEventListener(DRAGEND, listener))
} }
fun onDragOver(listener: SyntheticDragEventListener) { fun onDragOver(listener: SyntheticDragEventListener) {
registerEventListener(DragEventListener(DRAGOVER, listener)) registerEventListener(DragEventListener(DRAGOVER, listener))
} }
fun onDragEnter(listener: SyntheticDragEventListener) { fun onDragEnter(listener: SyntheticDragEventListener) {
registerEventListener(DragEventListener(DRAGENTER, listener)) registerEventListener(DragEventListener(DRAGENTER, listener))
} }
fun onDragLeave(listener: SyntheticDragEventListener) { fun onDragLeave(listener: SyntheticDragEventListener) {
registerEventListener(DragEventListener(DRAGLEAVE, listener)) registerEventListener(DragEventListener(DRAGLEAVE, listener))
} }
/* End of Drag Events */ /* End of Drag Events */
/* Clipboard Events */ /* Clipboard Events */
fun onCopy(listener: (SyntheticClipboardEvent) -> Unit) { fun onCopy(listener: (SyntheticClipboardEvent) -> Unit) {
registerEventListener(ClipboardEventListener(COPY, listener)) registerEventListener(ClipboardEventListener(COPY, listener))
} }
fun onCut(listener: (SyntheticClipboardEvent) -> Unit) { fun onCut(listener: (SyntheticClipboardEvent) -> Unit) {
registerEventListener(ClipboardEventListener(CUT, listener)) registerEventListener(ClipboardEventListener(CUT, listener))
} }
fun onPaste(listener: (SyntheticClipboardEvent) -> Unit) { fun onPaste(listener: (SyntheticClipboardEvent) -> Unit) {
registerEventListener(ClipboardEventListener(PASTE, listener)) registerEventListener(ClipboardEventListener(PASTE, listener))
} }
/* End of Clipboard Events */ /* End of Clipboard Events */
/* Keyboard Events */ /* Keyboard Events */
fun onKeyDown(listener: (SyntheticKeyboardEvent) -> Unit) { fun onKeyDown(listener: (SyntheticKeyboardEvent) -> Unit) {
registerEventListener(KeyboardEventListener(KEYDOWN, listener)) registerEventListener(KeyboardEventListener(KEYDOWN, listener))
} }
fun onKeyUp(listener: (SyntheticKeyboardEvent) -> Unit) { fun onKeyUp(listener: (SyntheticKeyboardEvent) -> Unit) {
registerEventListener(KeyboardEventListener(KEYUP, listener)) registerEventListener(KeyboardEventListener(KEYUP, listener))
} }
/* End of Keyboard Events */ /* End of Keyboard Events */
/* Focus Events */ /* Focus Events */
fun onFocus(listener: (SyntheticFocusEvent) -> Unit) { fun onFocus(listener: (SyntheticFocusEvent) -> Unit) {
registerEventListener(FocusEventListener(FOCUS, listener)) registerEventListener(FocusEventListener(FOCUS, listener))
} }
fun onBlur(listener: (SyntheticFocusEvent) -> Unit) { fun onBlur(listener: (SyntheticFocusEvent) -> Unit) {
registerEventListener(FocusEventListener(BLUR, listener)) registerEventListener(FocusEventListener(BLUR, listener))
} }
fun onFocusIn(listener: (SyntheticFocusEvent) -> Unit) { fun onFocusIn(listener: (SyntheticFocusEvent) -> Unit) {
registerEventListener(FocusEventListener(FOCUSIN, listener)) registerEventListener(FocusEventListener(FOCUSIN, listener))
} }
fun onFocusOut(listener: (SyntheticFocusEvent) -> Unit) { fun onFocusOut(listener: (SyntheticFocusEvent) -> Unit) {
registerEventListener(FocusEventListener(FOCUSOUT, listener)) registerEventListener(FocusEventListener(FOCUSOUT, listener))
} }
/* End of Focus Events */ /* End of Focus Events */
/* Touch Events */ /* Touch Events */
fun onTouchCancel(listener: (SyntheticTouchEvent) -> Unit) { fun onTouchCancel(listener: (SyntheticTouchEvent) -> Unit) {
registerEventListener(TouchEventListener(TOUCHCANCEL, listener)) registerEventListener(TouchEventListener(TOUCHCANCEL, listener))
} }
fun onTouchMove(listener: (SyntheticTouchEvent) -> Unit) { fun onTouchMove(listener: (SyntheticTouchEvent) -> Unit) {
registerEventListener(TouchEventListener(TOUCHMOVE, listener)) registerEventListener(TouchEventListener(TOUCHMOVE, listener))
} }
fun onTouchEnd(listener: (SyntheticTouchEvent) -> Unit) { fun onTouchEnd(listener: (SyntheticTouchEvent) -> Unit) {
registerEventListener(TouchEventListener(TOUCHEND, listener)) registerEventListener(TouchEventListener(TOUCHEND, listener))
} }
fun onTouchStart(listener: (SyntheticTouchEvent) -> Unit) { fun onTouchStart(listener: (SyntheticTouchEvent) -> Unit) {
registerEventListener(TouchEventListener(TOUCHSTART, listener)) registerEventListener(TouchEventListener(TOUCHSTART, listener))
} }
/* End of Touch Events */ /* End of Touch Events */
/* Animation Events */ /* Animation Events */
fun onAnimationEnd(listener: (SyntheticAnimationEvent) -> Unit) { fun onAnimationEnd(listener: (SyntheticAnimationEvent) -> Unit) {
registerEventListener(AnimationEventListener(ANIMATIONEND, listener)) registerEventListener(AnimationEventListener(ANIMATIONEND, listener))
} }
fun onAnimationIteration(listener: (SyntheticAnimationEvent) -> Unit) { fun onAnimationIteration(listener: (SyntheticAnimationEvent) -> Unit) {
registerEventListener(AnimationEventListener(ANIMATIONITERATION, listener)) registerEventListener(AnimationEventListener(ANIMATIONITERATION, listener))
} }
fun onAnimationStart(listener: (SyntheticAnimationEvent) -> Unit) { fun onAnimationStart(listener: (SyntheticAnimationEvent) -> Unit) {
registerEventListener(AnimationEventListener(ANIMATIONSTART, listener)) registerEventListener(AnimationEventListener(ANIMATIONSTART, listener))
} }
/* End of Animation Events */ /* End of Animation Events */
fun onScroll(listener: (SyntheticEvent<EventTarget>) -> Unit) { fun onScroll(listener: (SyntheticEvent<EventTarget>) -> Unit) {
registerEventListener(SyntheticEventListener(SCROLL, listener)) registerEventListener(SyntheticEventListener(SCROLL, listener))
} }
fun collectListeners(): List<SyntheticEventListener<*>> = listeners
/** /**
* [addEventListener] used for adding arbitrary events to the element. It resembles the standard DOM addEventListener method * [addEventListener] used for adding arbitrary events to the element. It resembles the standard DOM addEventListener method
* @param eventName - the name of the event * @param eventName - the name of the event
@ -211,30 +206,27 @@ interface EventsListenerScope {
) { ) {
registerEventListener(SyntheticEventListener(eventName, listener)) registerEventListener(SyntheticEventListener(eventName, listener))
} }
fun addEventListener( fun addEventListener(
eventName: String, eventName: String,
listener: (SyntheticEvent<EventTarget>) -> Unit listener: (SyntheticEvent<EventTarget>) -> Unit
) { ) {
registerEventListener(SyntheticEventListener(eventName, listener)) registerEventListener(SyntheticEventListener(eventName, listener))
} }
@ComposeWebInternalApi
fun copyListenersFrom(from: EventsListenerScope)
companion object { companion object {
const val COPY = "copy" const val COPY = "copy"
const val CUT = "cut" const val CUT = "cut"
const val PASTE = "paste" const val PASTE = "paste"
const val CONTEXTMENU = "contextmenu" const val CONTEXTMENU = "contextmenu"
const val CLICK = "click" const val CLICK = "click"
const val DBLCLICK = "dblclick" const val DBLCLICK = "dblclick"
const val FOCUS = "focus" const val FOCUS = "focus"
const val BLUR = "blur" const val BLUR = "blur"
const val FOCUSIN = "focusin" const val FOCUSIN = "focusin"
const val FOCUSOUT = "focusout" const val FOCUSOUT = "focusout"
const val KEYDOWN = "keydown" const val KEYDOWN = "keydown"
const val KEYUP = "keyup" const val KEYUP = "keyup"
const val MOUSEDOWN = "mousedown" const val MOUSEDOWN = "mousedown"
@ -247,22 +239,22 @@ interface EventsListenerScope {
const val WHEEL = "wheel" const val WHEEL = "wheel"
const val SCROLL = "scroll" const val SCROLL = "scroll"
const val SELECT = "select" const val SELECT = "select"
const val TOUCHCANCEL = "touchcancel" const val TOUCHCANCEL = "touchcancel"
const val TOUCHEND = "touchend" const val TOUCHEND = "touchend"
const val TOUCHMOVE = "touchmove" const val TOUCHMOVE = "touchmove"
const val TOUCHSTART = "touchstart" const val TOUCHSTART = "touchstart"
const val ANIMATIONCANCEL = "animationcancel" // firefox and safari only const val ANIMATIONCANCEL = "animationcancel" // firefox and safari only
const val ANIMATIONEND = "animationend" const val ANIMATIONEND = "animationend"
const val ANIMATIONITERATION = "animationiteration" const val ANIMATIONITERATION = "animationiteration"
const val ANIMATIONSTART = "animationstart" const val ANIMATIONSTART = "animationstart"
const val BEFOREINPUT = "beforeinput" const val BEFOREINPUT = "beforeinput"
const val INPUT = "input" const val INPUT = "input"
const val CHANGE = "change" const val CHANGE = "change"
const val INVALID = "invalid" const val INVALID = "invalid"
const val DRAG = "drag" const val DRAG = "drag"
const val DROP = "drop" const val DROP = "drop"
const val DRAGSTART = "dragstart" const val DRAGSTART = "dragstart"
@ -270,20 +262,22 @@ interface EventsListenerScope {
const val DRAGOVER = "dragover" const val DRAGOVER = "dragover"
const val DRAGENTER = "dragenter" const val DRAGENTER = "dragenter"
const val DRAGLEAVE = "dragleave" const val DRAGLEAVE = "dragleave"
const val SUBMIT = "submit" const val SUBMIT = "submit"
const val RESET = "reset" const val RESET = "reset"
} }
} }
open class EventsListenerScopeBuilder: EventsListenerScope { open class EventsListenerScopeBuilder : EventsListenerScope {
override val listeners: MutableList<SyntheticEventListener<*>> = mutableListOf() private val listeners: MutableList<SyntheticEventListener<*>> = mutableListOf()
override fun registerEventListener(listener: SyntheticEventListener<*>) { override fun registerEventListener(listener: SyntheticEventListener<*>) {
listeners.add(listener) listeners.add(listener)
} }
override fun copyListenersFrom(from: EventsListenerScope) { internal fun copyListenersFrom(from: EventsListenerScopeBuilder) {
listeners.addAll(from.listeners) listeners.addAll(from.listeners)
} }
internal fun collectListeners(): List<SyntheticEventListener<*>> = listeners
} }

5
web/core/src/jsMain/kotlin/org/jetbrains/compose/web/attributes/builders/InputAttrsScope.kt

@ -38,8 +38,9 @@ typealias InputAttrsBuilder<T> = InputAttrsScope<T>
* [onSelect] - add `select` event listener * [onSelect] - add `select` event listener
*/ */
class InputAttrsScope<ValueType>( class InputAttrsScope<ValueType>(
val inputType: InputType<ValueType> val inputType: InputType<ValueType>,
) : AttrsScopeBuilder<HTMLInputElement>() { attrsScope: AttrsScope<HTMLInputElement>
) : AttrsScope<HTMLInputElement> by attrsScope {
fun value(value: String): InputAttrsScope<ValueType> { fun value(value: String): InputAttrsScope<ValueType> {
when (inputType) { when (inputType) {

4
web/core/src/jsMain/kotlin/org/jetbrains/compose/web/attributes/builders/SelectAttrsScope.kt

@ -5,7 +5,7 @@
package androidx.compose.web.attributes package androidx.compose.web.attributes
import org.jetbrains.compose.web.attributes.AttrsScopeBuilder import org.jetbrains.compose.web.attributes.AttrsScope
import org.jetbrains.compose.web.attributes.EventsListenerScope.Companion.CHANGE import org.jetbrains.compose.web.attributes.EventsListenerScope.Companion.CHANGE
import org.jetbrains.compose.web.attributes.EventsListenerScope.Companion.INPUT import org.jetbrains.compose.web.attributes.EventsListenerScope.Companion.INPUT
import org.jetbrains.compose.web.attributes.SyntheticEventListener import org.jetbrains.compose.web.attributes.SyntheticEventListener
@ -20,7 +20,7 @@ import org.w3c.dom.events.Event
) )
typealias SelectAttrsBuilder = SelectAttrsScope typealias SelectAttrsBuilder = SelectAttrsScope
class SelectAttrsScope : AttrsScopeBuilder<HTMLSelectElement>() { class SelectAttrsScope(attrsScope: AttrsScope<HTMLSelectElement>) : AttrsScope<HTMLSelectElement> by attrsScope {
fun onInput( fun onInput(
listener: (SyntheticInputEvent<String?, HTMLSelectElement>) -> Unit listener: (SyntheticInputEvent<String?, HTMLSelectElement>) -> Unit

2
web/core/src/jsMain/kotlin/org/jetbrains/compose/web/attributes/builders/TextAreaAttrsScope.kt

@ -26,7 +26,7 @@ import org.w3c.dom.HTMLTextAreaElement
) )
typealias TextAreaAttrsBuilder = TextAreaAttrsScope typealias TextAreaAttrsBuilder = TextAreaAttrsScope
class TextAreaAttrsScope : AttrsScopeBuilder<HTMLTextAreaElement>() { class TextAreaAttrsScope(attrsScope: AttrsScope<HTMLTextAreaElement>) : AttrsScope<HTMLTextAreaElement> by attrsScope {
fun value(value: String): AttrsScope<HTMLTextAreaElement> { fun value(value: String): AttrsScope<HTMLTextAreaElement> {
prop(setInputValue, value) prop(setInputValue, value)

21
web/core/src/jsMain/kotlin/org/jetbrains/compose/web/css/StyleScope.kt

@ -10,13 +10,19 @@ package org.jetbrains.compose.web.css
import org.jetbrains.compose.web.internal.runtime.ComposeWebInternalApi import org.jetbrains.compose.web.internal.runtime.ComposeWebInternalApi
import kotlin.properties.ReadOnlyProperty import kotlin.properties.ReadOnlyProperty
@Deprecated(
message = "Renamed to StyleScope",
replaceWith = ReplaceWith("StyleScope", "org.jetbrains.compose.web.css.StyleScope")
)
typealias StyleBuilder = StyleScope
/** /**
* StyleBuilder serves for two main purposes. Passed as a builder context (in [AttrsScope]), it * StyleScope serves for two main purposes. Passed as a builder context (in [AttrsScope]), it
* makes it possible to: * makes it possible to:
* 1. Add inlined css properties to the element (@see [property]) * 1. Add inlined css properties to the element (@see [property])
* 2. Set values to CSS variables (@see [variable]) * 2. Set values to CSS variables (@see [variable])
*/ */
interface StyleBuilder { interface StyleScope {
/** /**
* Adds arbitrary CSS property to the inline style of the element * Adds arbitrary CSS property to the inline style of the element
* @param propertyName - the name of css property as [per spec](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference) * @param propertyName - the name of css property as [per spec](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference)
@ -131,20 +137,14 @@ interface StyleHolder {
val variables: StylePropertyList val variables: StylePropertyList
} }
interface StyleScope : StyleBuilder, StyleHolder {
@ComposeWebInternalApi
fun copyFrom(sb: StyleScope)
}
@Deprecated( @Deprecated(
message = "Renamed to StyleScopeBuilder", message = "Renamed to StyleScopeBuilder",
replaceWith = ReplaceWith("StyleScopeBuilder", "org.jetbrains.compose.web.css.StyleScopeBuilder") replaceWith = ReplaceWith("StyleScopeBuilder", "org.jetbrains.compose.web.css.StyleScopeBuilder")
) )
typealias StyleBuilderImpl = StyleScopeBuilder typealias StyleBuilderImpl = StyleScopeBuilder
@OptIn(ComposeWebInternalApi::class)
@Suppress("EqualsOrHashCode") @Suppress("EqualsOrHashCode")
open class StyleScopeBuilder : StyleScope { open class StyleScopeBuilder : StyleScope, StyleHolder {
override val properties: MutableStylePropertyList = mutableListOf() override val properties: MutableStylePropertyList = mutableListOf()
override val variables: MutableStylePropertyList = mutableListOf() override val variables: MutableStylePropertyList = mutableListOf()
@ -164,7 +164,8 @@ open class StyleScopeBuilder : StyleScope {
} else false } else false
} }
override fun copyFrom(sb: StyleScope) { @ComposeWebInternalApi
internal fun copyFrom(sb: StyleHolder) {
properties.addAll(sb.properties) properties.addAll(sb.properties)
variables.addAll(sb.variables) variables.addAll(sb.variables)
} }

5
web/core/src/jsMain/kotlin/org/jetbrains/compose/web/elements/Base.kt

@ -127,7 +127,10 @@ fun <TElement : Element> TagElement(
set(attrsScope.classes, DomElementWrapper::updateClasses) set(attrsScope.classes, DomElementWrapper::updateClasses)
set(attrsScope.styleScope, DomElementWrapper::updateStyleDeclarations) set(attrsScope.styleScope, DomElementWrapper::updateStyleDeclarations)
set(attrsScope.collect(), DomElementWrapper::updateAttrs) set(attrsScope.collect(), DomElementWrapper::updateAttrs)
set(attrsScope.collectListeners(), DomElementWrapper::updateEventListeners) set(
attrsScope.eventsListenerScopeBuilder.collectListeners(),
DomElementWrapper::updateEventListeners
)
set(attrsScope.propertyUpdates, DomElementWrapper::updateProperties) set(attrsScope.propertyUpdates, DomElementWrapper::updateProperties)
} }
}, },

14
web/core/src/jsMain/kotlin/org/jetbrains/compose/web/elements/Elements.kt

@ -598,11 +598,7 @@ fun Select(
applyAttrs = { applyAttrs = {
if (multiple) multiple() if (multiple) multiple()
if (attrs != null) { if (attrs != null) {
val selectAttrsBuilder = with(SelectAttrsScope()) { SelectAttrsScope(this).attrs()
attrs()
this
}
copyFrom(selectAttrsBuilder)
} }
}, },
content = content content = content
@ -682,7 +678,7 @@ fun TextArea(
TagElement( TagElement(
elementBuilder = TextArea, elementBuilder = TextArea,
applyAttrs = { applyAttrs = {
val textAreaAttrsBuilder = TextAreaAttrsScope() val textAreaAttrsBuilder = TextAreaAttrsScope(this)
textAreaAttrsBuilder.onInput { textAreaAttrsBuilder.onInput {
// controlled state needs to be restored after every input // controlled state needs to be restored after every input
keyForRestoringControlledState.value = keyForRestoringControlledState.value + 1 keyForRestoringControlledState.value = keyForRestoringControlledState.value + 1
@ -693,8 +689,6 @@ fun TextArea(
if (firstProvidedValueWasNotNull) { if (firstProvidedValueWasNotNull) {
textAreaAttrsBuilder.value(value ?: "") textAreaAttrsBuilder.value(value ?: "")
} }
this.copyFrom(textAreaAttrsBuilder)
}, },
content = { content = {
DisposableEffect(keyForRestoringControlledState.value) { DisposableEffect(keyForRestoringControlledState.value) {
@ -1006,7 +1000,7 @@ fun <K> Input(
TagElement( TagElement(
elementBuilder = Input, elementBuilder = Input,
applyAttrs = { applyAttrs = {
val inputAttrsBuilder = InputAttrsScope(type) val inputAttrsBuilder = InputAttrsScope(type, this)
inputAttrsBuilder.type(type) inputAttrsBuilder.type(type)
inputAttrsBuilder.onInput { inputAttrsBuilder.onInput {
// controlled state needs to be restored after every input // controlled state needs to be restored after every input
@ -1014,8 +1008,6 @@ fun <K> Input(
} }
inputAttrsBuilder.attrs() inputAttrsBuilder.attrs()
this.copyFrom(inputAttrsBuilder)
}, },
content = { content = {
if (type == InputType.Radio) { if (type == InputType.Radio) {

7
web/core/src/jsTest/kotlin/elements/AttributesTests.kt

@ -164,7 +164,10 @@ class AttributesTests {
assertEquals(attrsScopeCopyFrom.styleScope, copyToAttrsScope.styleScope) assertEquals(attrsScopeCopyFrom.styleScope, copyToAttrsScope.styleScope)
assertEquals(attrsScopeCopyFrom.refEffect, copyToAttrsScope.refEffect) assertEquals(attrsScopeCopyFrom.refEffect, copyToAttrsScope.refEffect)
assertEquals(attrsScopeCopyFrom.propertyUpdates, copyToAttrsScope.propertyUpdates) assertEquals(attrsScopeCopyFrom.propertyUpdates, copyToAttrsScope.propertyUpdates)
assertEquals(attrsScopeCopyFrom.collectListeners(), copyToAttrsScope.collectListeners()) assertEquals(
attrsScopeCopyFrom.eventsListenerScopeBuilder.collectListeners(),
copyToAttrsScope.eventsListenerScopeBuilder.collectListeners()
)
} }
@Test @Test
@ -186,7 +189,7 @@ class AttributesTests {
assertEquals("id1", copyToAttrsScope.attributesMap["id"]) assertEquals("id1", copyToAttrsScope.attributesMap["id"])
assertEquals(StyleScopeBuilder().apply { width(100.px) }, copyToAttrsScope.styleScope) assertEquals(StyleScopeBuilder().apply { width(100.px) }, copyToAttrsScope.styleScope)
val listeners = copyToAttrsScope.collectListeners() val listeners = copyToAttrsScope.eventsListenerScopeBuilder.collectListeners()
assertEquals(1, listeners.size) assertEquals(1, listeners.size)
assertEquals("click", listeners[0].event) assertEquals("click", listeners[0].event)
} }

1
web/settings.gradle.kts

@ -77,7 +77,6 @@ if (extra["compose.web.tests.skip.benchmarks"]!!.toString().toBoolean() != true)
if (extra["compose.web.buildSamples"]!!.toString().toBoolean() == true) { if (extra["compose.web.buildSamples"]!!.toString().toBoolean() == true) {
println("building with examples") println("building with examples")
module(":examples:falling-balls-web", "../examples/falling-balls-web")
module(":examples:compose-web-lp", "../examples/web-landing") module(":examples:compose-web-lp", "../examples/web-landing")
module(":examples:web-compose-bird", "../examples/web-compose-bird") module(":examples:web-compose-bird", "../examples/web-compose-bird")
module(":examples:web-with-react", "../examples/web-with-react") module(":examples:web-with-react", "../examples/web-with-react")

Loading…
Cancel
Save