mirror of
https://github.com/jlengrand/compose-multiplatform.git
synced 2026-03-10 08:11:20 +00:00
Add support for transition in CSS api. (#2228)
* web: Support for transition in CSS api. * Use proper name for Transitions class, fix formatting. * web: add ExperimentalComposeWebApi on transitions CSS API. * web: Add documentation for transitions CSS API. * fix: Apply all suggested changes. * web: Add unit tests to transitions CSS API. * fix: Update documentation with new methods names.
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright 2020-2022 JetBrains s.r.o. and respective authors and developers.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.compose.web.css
|
||||
|
||||
import org.jetbrains.compose.web.ExperimentalComposeWebApi
|
||||
|
||||
@ExperimentalComposeWebApi
|
||||
data class Transition(
|
||||
var property: String? = null,
|
||||
var duration: CSSSizeValue<out CSSUnitTime>? = null,
|
||||
var timingFunction: AnimationTimingFunction? = null,
|
||||
var delay: CSSSizeValue<out CSSUnitTime>? = null,
|
||||
) {
|
||||
override fun toString(): String {
|
||||
if (property == null) return ""
|
||||
var result = property!!
|
||||
|
||||
duration?.let { result += " $it" }
|
||||
timingFunction?.let { result += " $it" }
|
||||
delay?.let { result += " $it" }
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
@ExperimentalComposeWebApi
|
||||
fun Transition.duration(value: CSSSizeValue<out CSSUnitTime>): Unit = run { duration = value }
|
||||
|
||||
@ExperimentalComposeWebApi
|
||||
fun Transition.timingFunction(value: AnimationTimingFunction): Unit = run { timingFunction = value }
|
||||
|
||||
@ExperimentalComposeWebApi
|
||||
fun Transition.delay(value: CSSSizeValue<out CSSUnitTime>): Unit = run { delay = value }
|
||||
|
||||
@ExperimentalComposeWebApi
|
||||
data class Transitions(
|
||||
var transitions: List<Transition> = emptyList(),
|
||||
private var defaultDuration: CSSSizeValue<out CSSUnitTime>? = null,
|
||||
private var defaultTimingFunction: AnimationTimingFunction? = null,
|
||||
private var defaultDelay: CSSSizeValue<out CSSUnitTime>? = null,
|
||||
) {
|
||||
override fun toString() =
|
||||
transitions.distinctBy {
|
||||
it.property
|
||||
}.joinToString(", ") {
|
||||
it.apply {
|
||||
if (defaultDelay != null && delay == null) delay = defaultDelay!!
|
||||
if (defaultDuration != null && duration == null) duration = defaultDuration!!
|
||||
if (defaultTimingFunction != null && timingFunction == null) timingFunction = defaultTimingFunction!!
|
||||
}.toString()
|
||||
}
|
||||
|
||||
inline operator fun String.invoke(block: Transition.() -> Unit): Unit = Transition().apply(block).let {
|
||||
it.property = this
|
||||
transitions += it
|
||||
}
|
||||
|
||||
inline operator fun Iterable<String>.invoke(block: Transition.() -> Unit): Unit = Transition().apply(block).let { transition ->
|
||||
forEach {
|
||||
transitions += transition.copy(property = it)
|
||||
}
|
||||
}
|
||||
|
||||
inline operator fun Array<out String>.invoke(block: Transition.() -> Unit): Unit = Transition().apply(block).let { transition ->
|
||||
forEach {
|
||||
transitions += transition.copy(property = it)
|
||||
}
|
||||
}
|
||||
|
||||
inline fun properties(vararg properties: String, block: Transition.() -> Unit = {}): Unit = properties.invoke(block)
|
||||
|
||||
inline fun all(block: Transition.() -> Unit): Unit = Transition().apply(block).let { transition ->
|
||||
transition.property = "all"
|
||||
transitions += transition
|
||||
}
|
||||
|
||||
fun defaultDuration(value: CSSSizeValue<out CSSUnitTime>): Unit = run { defaultDuration = value }
|
||||
fun defaultTimingFunction(value: AnimationTimingFunction): Unit = run { defaultTimingFunction = value }
|
||||
fun defaultDelay(value: CSSSizeValue<out CSSUnitTime>): Unit = run { defaultDelay = value }
|
||||
}
|
||||
|
||||
@ExperimentalComposeWebApi
|
||||
/**
|
||||
* Examples:
|
||||
* ```
|
||||
* transitions {
|
||||
* "width" { duration(1.s) }
|
||||
* }
|
||||
*
|
||||
* transitions {
|
||||
* defaultDuration(.5.s)
|
||||
* defaultTimingFunction(AnimationTimingFunction.EaseInOut)
|
||||
* defaultProperties("width", "height")
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/CSS/transition
|
||||
*/
|
||||
inline fun StyleScope.transitions(transitions: Transitions.() -> Unit) {
|
||||
val transitionsValue = Transitions().apply(transitions)
|
||||
property("transition", transitionsValue.toString())
|
||||
}
|
||||
80
web/core/src/jsTest/kotlin/css/TransitionsTests.kt
Normal file
80
web/core/src/jsTest/kotlin/css/TransitionsTests.kt
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2020-2022 JetBrains s.r.o. and respective authors and developers.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.compose.web.core.tests.css
|
||||
|
||||
import org.jetbrains.compose.web.ExperimentalComposeWebApi
|
||||
import org.jetbrains.compose.web.css.AnimationTimingFunction
|
||||
import org.jetbrains.compose.web.css.delay
|
||||
import org.jetbrains.compose.web.css.duration
|
||||
import org.jetbrains.compose.web.css.s
|
||||
import org.jetbrains.compose.web.css.timingFunction
|
||||
import org.jetbrains.compose.web.css.transitions
|
||||
import org.jetbrains.compose.web.dom.Div
|
||||
import org.jetbrains.compose.web.testutils.runTest
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
@ExperimentalComposeWebApi
|
||||
class TransitionsTests {
|
||||
@Test
|
||||
fun duration() = runTest {
|
||||
composition {
|
||||
Div({ style { transitions { "width" { duration(1.s) } }}})
|
||||
}
|
||||
|
||||
assertEquals("width 1s ease 0s", nextChild().style.transition)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun multipleProperties() = runTest {
|
||||
composition {
|
||||
Div({ style { transitions { "width" { duration(1.s) }; "height" { duration(2.s) } }}})
|
||||
}
|
||||
|
||||
assertEquals("width 1s ease 0s, height 2s ease 0s", nextChild().style.transition)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun allProperties() = runTest {
|
||||
composition {
|
||||
Div({ style { transitions { all { duration(1.s) } }}})
|
||||
}
|
||||
|
||||
assertEquals("all 1s ease 0s", nextChild().style.transition)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun timingFunction() = runTest {
|
||||
composition {
|
||||
Div({ style { transitions { "width" { duration(1.s); timingFunction(AnimationTimingFunction.EaseInOut) }}}})
|
||||
}
|
||||
|
||||
assertEquals("width 1s ease-in-out 0s", nextChild().style.transition)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun delay() = runTest {
|
||||
composition {
|
||||
Div({ style { transitions { "width" { duration(1.s); delay(2.s) }}}})
|
||||
}
|
||||
|
||||
assertEquals("width 1s ease 2s", nextChild().style.transition)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun properties() = runTest {
|
||||
composition {
|
||||
Div({ style { transitions { defaultDuration(1.s); properties("width", "height") }}})
|
||||
Div({ style { transitions { defaultDuration(1.s); properties("width, height"); "width" { duration(2.s) }}}})
|
||||
val myList = listOf("width", "height")
|
||||
Div({ style { transitions { defaultDuration(1.s); myList { duration(2.s) }}}})
|
||||
}
|
||||
|
||||
assertEquals("width 1s ease 0s, height 1s ease 0s", nextChild().style.transition)
|
||||
assertEquals("width 0s ease 0s, height 1s ease 0s, width 2s ease 0s", nextChild().style.transition)
|
||||
assertEquals("width 2s ease 0s, height 2s ease 0s", nextChild().style.transition)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user