aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/core/Types.kt1
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/core/Widget.kt199
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/utils/Utils.kt23
-rw-r--r--src/test/kotlin/test/pl/treksoft/kvision/utils/UtilsSpec.kt9
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")
+ }
+ }
}