diff options
Diffstat (limited to 'src')
4 files changed, 222 insertions, 10 deletions
diff --git a/src/main/kotlin/pl/treksoft/kvision/core/Types.kt b/src/main/kotlin/pl/treksoft/kvision/core/Types.kt index 9248020c..e59a5eeb 100644 --- a/src/main/kotlin/pl/treksoft/kvision/core/Types.kt +++ b/src/main/kotlin/pl/treksoft/kvision/core/Types.kt @@ -42,4 +42,3 @@ typealias StringBoolPair = Pair<String, Boolean> * This type is used for defining CSS dimensions (width, heights, margins, paddings, etc.). */ typealias CssSize = Pair<Number, UNIT> - diff --git a/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt b/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt index c0e684ba..ba4db0cc 100644 --- a/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt +++ b/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt @@ -35,17 +35,14 @@ import pl.treksoft.kvision.i18n.I18n import pl.treksoft.kvision.i18n.I18n.trans import pl.treksoft.kvision.panel.Root import pl.treksoft.kvision.state.ObservableState -import pl.treksoft.kvision.utils.SnOn -import pl.treksoft.kvision.utils.emptyOn -import pl.treksoft.kvision.utils.hooks -import pl.treksoft.kvision.utils.on -import pl.treksoft.kvision.utils.set -import pl.treksoft.kvision.utils.snAttrs -import pl.treksoft.kvision.utils.snClasses -import pl.treksoft.kvision.utils.snOpt -import pl.treksoft.kvision.utils.snStyle +import pl.treksoft.kvision.utils.* import kotlin.reflect.KProperty +enum class Easing(internal val easing: String) { + SWING("swing"), + LINEAR("linear") +} + /** * Base widget class. The parent of all component classes. * @@ -439,6 +436,162 @@ open class Widget(classes: Set<String> = setOf()) : StyledComponent(), Component } /** + * Shows current widget with animation effect. + * @param duration a duration of the animation + * @param easing an easing function to use + * @param complete a callback function called after the animation completes + * @return current widget + */ + open fun showAnim( + duration: Int = 400, + easing: Easing = Easing.SWING, + complete: (() -> Unit)? = null + ): Widget { + this.display = Display.NONE + this.visible = true + val jq = getElementJQuery() + if (jq != null) { + jq.show(duration, easing.easing) { + this.display = null + complete?.invoke() + } + } else { + this.display = null + complete?.invoke() + } + return this + } + + /** + * Hides current widget with animation effect. + * @param duration a duration of the animation + * @param easing an easing function to use + * @param complete a callback function called after the animation completes + * @return current widget + */ + open fun hideAnim( + duration: Int = 400, + easing: Easing = Easing.SWING, + complete: (() -> Unit)? = null + ): Widget { + val jq = getElementJQuery() + if (jq != null) { + jq.hide(duration, easing.easing) { + this.visible = false + complete?.invoke() + } + } else { + this.visible = false + complete?.invoke() + } + return this + } + + /** + * Shows current widget with slide down effect. + * @param duration a duration of the animation + * @param easing an easing function to use + * @param complete a callback function called after the animation completes + * @return current widget + */ + open fun slideDown( + duration: Int = 400, + easing: Easing = Easing.SWING, + complete: (() -> Unit)? = null + ): Widget { + this.display = Display.NONE + this.visible = true + val jq = getElementJQuery() + if (jq != null) { + jq.slideDown(duration, easing.easing) { + this.display = null + complete?.invoke() + } + } else { + this.display = null + complete?.invoke() + } + return this + } + + /** + * Hides current widget with slide up effect. + * @param duration a duration of the animation + * @param easing an easing function to use + * @param complete a callback function called after the animation completes + * @return current widget + */ + open fun slideUp( + duration: Int = 400, + easing: Easing = Easing.SWING, + complete: (() -> Unit)? = null + ): Widget { + val jq = getElementJQuery() + if (jq != null) { + jq.slideUp(duration, easing.easing) { + this.visible = false + complete?.invoke() + } + } else { + this.visible = false + complete?.invoke() + } + return this + } + + /** + * Shows current widget with fade in effect. + * @param duration a duration of the animation + * @param easing an easing function to use + * @param complete a callback function called after the animation completes + * @return current widget + */ + open fun fadeIn( + duration: Int = 400, + easing: Easing = Easing.SWING, + complete: (() -> Unit)? = null + ): Widget { + this.display = Display.NONE + this.visible = true + val jq = getElementJQuery() + if (jq != null) { + jq.fadeIn(duration, easing.easing) { + this.display = null + complete?.invoke() + } + } else { + this.display = null + complete?.invoke() + } + return this + } + + /** + * Hides current widget with fade out effect. + * @param duration a duration of the animation + * @param easing an easing function to use + * @param complete a callback function called after the animation completes + * @return current widget + */ + open fun fadeOut( + duration: Int = 400, + easing: Easing = Easing.SWING, + complete: (() -> Unit)? = null + ): Widget { + val jq = getElementJQuery() + if (jq != null) { + jq.fadeOut(duration, easing.easing) { + this.visible = false + complete?.invoke() + } + } else { + this.visible = false + complete?.invoke() + } + return this + } + + /** * Enables tooltip for the current widget. * @param options tooltip options * @return current widget @@ -755,6 +908,34 @@ open class Widget(classes: Set<String> = setOf()) : StyledComponent(), Component } /** + * Animate the widget changing CSS properties. + * @param duration a duration of the animation + * @param easing an easing function to use + * @param complete a callback function called after the animation completes + * @param styles changing properties values + */ + open fun animate( + duration: Int = 400, + easing: Easing = Easing.SWING, + complete: (() -> Unit)? = null, + styles: StyledComponent.() -> Unit + ) { + val widget = Widget() + widget.styles() + val stylesList = widget.getSnStyle() + val obj = js("{}") + stylesList.forEach { (key, value) -> + obj[key.toCamelCase()] = value + } + @Suppress("UnsafeCastFromDynamic") + getElementJQuery()?.animate(obj, duration, easing.easing) { + widget.dispose() + this.styles() + complete?.invoke() + } + } + + /** * @suppress * Internal function */ diff --git a/src/main/kotlin/pl/treksoft/kvision/utils/Utils.kt b/src/main/kotlin/pl/treksoft/kvision/utils/Utils.kt index e2833630..995b0466 100644 --- a/src/main/kotlin/pl/treksoft/kvision/utils/Utils.kt +++ b/src/main/kotlin/pl/treksoft/kvision/utils/Utils.kt @@ -161,6 +161,20 @@ fun CssSize.asString(): String { } } +/** + * Extension operator to increase CssSize units. + */ +operator fun CssSize?.plus(i: Number): CssSize { + return this?.let { CssSize(it.first.toDouble() + i.toDouble(), it.second) } ?: CssSize(i, UNIT.px) +} + +/** + * Extension operator to decrease CssSize units. + */ +operator fun CssSize?.minus(i: Number): CssSize { + return this?.let { CssSize(it.first.toDouble() - i.toDouble(), it.second) } ?: CssSize(i, UNIT.px) +} + private val hex = arrayOf("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f") /** @@ -208,3 +222,12 @@ val String?.set: Set<String> get() { return this?.split(Regex("\\s+"))?.toSet() ?: setOf() } + +/** + * Utility extension function to convert string from kebab-case to camelCase. + */ +fun String.toCamelCase(): String { + return this.replace(Regex("(\\-\\w)")) { + it.value.drop(1).toUpperCase() + } +} diff --git a/src/test/kotlin/test/pl/treksoft/kvision/utils/UtilsSpec.kt b/src/test/kotlin/test/pl/treksoft/kvision/utils/UtilsSpec.kt index 36217dd7..2bf63aaa 100644 --- a/src/test/kotlin/test/pl/treksoft/kvision/utils/UtilsSpec.kt +++ b/src/test/kotlin/test/pl/treksoft/kvision/utils/UtilsSpec.kt @@ -23,6 +23,7 @@ package test.pl.treksoft.kvision.utils import pl.treksoft.kvision.types.toDateF import pl.treksoft.kvision.types.toStringF +import pl.treksoft.kvision.utils.toCamelCase import pl.treksoft.kvision.utils.toHexString import test.pl.treksoft.kvision.SimpleSpec import kotlin.js.Date @@ -72,4 +73,12 @@ class UtilsSpec : SimpleSpec { assertEquals("$y-$m2-$d2 $h2:$min2:$sec2", res, "Should convert Date value to String") } } + + @Test + fun toCamelCase() { + run { + val marginTop = "margin-top".toCamelCase() + assertEquals("marginTop", marginTop, "Should convert a kebab-case string to camelCase") + } + } } |