mirror of
https://github.com/InsanusMokrassar/MicroUtils.git
synced 2024-12-26 18:47:17 +00:00
commit
210e32bed4
12
CHANGELOG.md
12
CHANGELOG.md
@ -1,5 +1,17 @@
|
||||
# Changelog
|
||||
|
||||
## 0.2.3
|
||||
|
||||
* `Versions`
|
||||
* `Coroutines`: `1.3.9` -> `1.4.0`
|
||||
* `Exposed`: `0.27.1` -> `0.28.1`
|
||||
* `Common`
|
||||
* `K/JS`
|
||||
* Add several extensions for `Element` objects to detect that object is on screen viewport
|
||||
* Add several extensions for `Element` objects to detect object visibility
|
||||
* `Coroutines`
|
||||
* `BroadcastStateFlow` now use different strategy for getting of state and implements `replayCache`
|
||||
|
||||
## 0.2.2
|
||||
|
||||
* `Repos`
|
||||
|
@ -0,0 +1,43 @@
|
||||
package dev.inmo.micro_utils.common
|
||||
|
||||
import kotlinx.browser.window
|
||||
import org.w3c.dom.DOMRect
|
||||
import org.w3c.dom.Element
|
||||
|
||||
val DOMRect.isOnScreenByLeftEdge: Boolean
|
||||
get() = left >= 0 && left <= window.innerWidth
|
||||
inline val Element.isOnScreenByLeftEdge
|
||||
get() = getBoundingClientRect().isOnScreenByLeftEdge
|
||||
|
||||
val DOMRect.isOnScreenByRightEdge: Boolean
|
||||
get() = right >= 0 && right <= window.innerWidth
|
||||
inline val Element.isOnScreenByRightEdge
|
||||
get() = getBoundingClientRect().isOnScreenByRightEdge
|
||||
|
||||
internal val DOMRect.isOnScreenHorizontally: Boolean
|
||||
get() = isOnScreenByLeftEdge || isOnScreenByRightEdge
|
||||
|
||||
|
||||
val DOMRect.isOnScreenByTopEdge: Boolean
|
||||
get() = top >= 0 && top <= window.innerHeight
|
||||
inline val Element.isOnScreenByTopEdge
|
||||
get() = getBoundingClientRect().isOnScreenByTopEdge
|
||||
|
||||
val DOMRect.isOnScreenByBottomEdge: Boolean
|
||||
get() = bottom >= 0 && bottom <= window.innerHeight
|
||||
inline val Element.isOnScreenByBottomEdge
|
||||
get() = getBoundingClientRect().isOnScreenByBottomEdge
|
||||
|
||||
internal val DOMRect.isOnScreenVertically: Boolean
|
||||
get() = isOnScreenByLeftEdge || isOnScreenByRightEdge
|
||||
|
||||
|
||||
val DOMRect.isOnScreenFully: Boolean
|
||||
get() = isOnScreenByLeftEdge && isOnScreenByTopEdge && isOnScreenByRightEdge && isOnScreenByBottomEdge
|
||||
val Element.isOnScreenFully: Boolean
|
||||
get() = getBoundingClientRect().isOnScreenFully
|
||||
|
||||
val DOMRect.isOnScreen: Boolean
|
||||
get() = isOnScreenFully || (isOnScreenHorizontally && isOnScreenVertically)
|
||||
inline val Element.isOnScreen: Boolean
|
||||
get() = getBoundingClientRect().isOnScreen
|
@ -0,0 +1,48 @@
|
||||
package dev.inmo.micro_utils.common
|
||||
|
||||
import kotlinx.browser.window
|
||||
import org.w3c.dom.Element
|
||||
import org.w3c.dom.css.CSSStyleDeclaration
|
||||
|
||||
sealed class Visibility
|
||||
object Visible : Visibility()
|
||||
object Invisible : Visibility()
|
||||
object Gone : Visibility()
|
||||
|
||||
var CSSStyleDeclaration.visibilityState: Visibility
|
||||
get() = when {
|
||||
display == "none" -> Gone
|
||||
visibility == "hidden" -> Invisible
|
||||
else -> Visible
|
||||
}
|
||||
set(value) {
|
||||
when (value) {
|
||||
Visible -> {
|
||||
if (display == "none") {
|
||||
display = "initial"
|
||||
}
|
||||
visibility = "visible"
|
||||
}
|
||||
Invisible -> {
|
||||
if (display == "none") {
|
||||
display = "initial"
|
||||
}
|
||||
visibility = "hidden"
|
||||
}
|
||||
Gone -> {
|
||||
display = "none"
|
||||
}
|
||||
}
|
||||
}
|
||||
inline var Element.visibilityState: Visibility
|
||||
get() = window.getComputedStyle(this).visibilityState
|
||||
set(value) {
|
||||
window.getComputedStyle(this).visibilityState = value
|
||||
}
|
||||
|
||||
inline val Element.isVisible: Boolean
|
||||
get() = visibilityState == Visible
|
||||
inline val Element.isInvisible: Boolean
|
||||
get() = visibilityState == Invisible
|
||||
inline val Element.isGone: Boolean
|
||||
get() = visibilityState == Gone
|
@ -5,29 +5,59 @@ import kotlinx.coroutines.channels.BroadcastChannel
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
||||
const val defaultBroadcastStateFlowReplayCacheSize = 1
|
||||
|
||||
class BroadcastStateFlow<T> internal constructor(
|
||||
parentFlow: Flow<T>,
|
||||
private val stateGetter: () -> T
|
||||
initial: T,
|
||||
replayCacheSize: Int = defaultBroadcastStateFlowReplayCacheSize,
|
||||
replayScope: CoroutineScope
|
||||
) : StateFlow<T>, Flow<T> by parentFlow {
|
||||
private val deque = ArrayDeque<T>(1).also {
|
||||
it.add(initial)
|
||||
}
|
||||
override val replayCache: List<T>
|
||||
get() = deque.toList()
|
||||
override val value: T
|
||||
get() = stateGetter()
|
||||
}
|
||||
get() = deque.last()
|
||||
|
||||
fun <T> BroadcastChannel<T>.asStateFlow(value: T, scope: CoroutineScope): StateFlow<T> = asFlow().let {
|
||||
var state: T = value
|
||||
it.onEach { state = it }.launchIn(scope)
|
||||
BroadcastStateFlow(it) {
|
||||
state
|
||||
init {
|
||||
if (replayCacheSize < 1) {
|
||||
error("Replay cache size can't be less than 1, but was $replayCacheSize")
|
||||
}
|
||||
parentFlow.onEach {
|
||||
deque.addLast(it)
|
||||
if (deque.size > replayCacheSize) {
|
||||
deque.removeFirst()
|
||||
}
|
||||
}.launchIn(replayScope)
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> BroadcastChannel<T?>.asStateFlow(scope: CoroutineScope): StateFlow<T?> = asStateFlow(null, scope)
|
||||
fun <T> BroadcastChannel<T>.asStateFlow(
|
||||
value: T,
|
||||
scope: CoroutineScope,
|
||||
replayCacheSize: Int = defaultBroadcastStateFlowReplayCacheSize
|
||||
): StateFlow<T> = BroadcastStateFlow(asFlow(), value, replayCacheSize, scope)
|
||||
|
||||
fun <T> broadcastStateFlow(initial: T, scope: CoroutineScope, channelSize: Int = Channel.BUFFERED) = BroadcastChannel<T>(
|
||||
fun <T> BroadcastChannel<T?>.asStateFlow(
|
||||
scope: CoroutineScope,
|
||||
replayCacheSize: Int = defaultBroadcastStateFlowReplayCacheSize
|
||||
): StateFlow<T?> = asStateFlow(null, scope, replayCacheSize)
|
||||
|
||||
fun <T> broadcastStateFlow(
|
||||
initial: T, scope: CoroutineScope,
|
||||
channelSize: Int = Channel.BUFFERED,
|
||||
replayCacheSize: Int = defaultBroadcastStateFlowReplayCacheSize
|
||||
) = BroadcastChannel<T>(
|
||||
channelSize
|
||||
).let {
|
||||
it to it.asStateFlow(initial, scope)
|
||||
it to it.asStateFlow(initial, scope, replayCacheSize)
|
||||
}
|
||||
|
||||
fun <T> broadcastStateFlow(scope: CoroutineScope, channelSize: Int = Channel.BUFFERED) = broadcastStateFlow<T?>(null, scope, channelSize)
|
||||
fun <T> broadcastStateFlow(
|
||||
scope: CoroutineScope,
|
||||
channelSize: Int = Channel.BUFFERED,
|
||||
replayCacheSize: Int = defaultBroadcastStateFlowReplayCacheSize
|
||||
) = broadcastStateFlow<T?>(null, scope, channelSize, replayCacheSize)
|
||||
|
||||
|
88
dokka/build.gradle
Normal file
88
dokka/build.gradle
Normal file
@ -0,0 +1,88 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenLocal()
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
|
||||
classpath "org.jetbrains.dokka:dokka-gradle-plugin:$dokka_version"
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id "org.jetbrains.kotlin.multiplatform"
|
||||
id "org.jetbrains.kotlin.plugin.serialization"
|
||||
id "org.jetbrains.dokka" version "$dokka_version"
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvm()
|
||||
js(BOTH) {
|
||||
browser()
|
||||
nodejs()
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
commonMain {
|
||||
dependencies {
|
||||
implementation kotlin('stdlib')
|
||||
|
||||
project.parent.subprojects.forEach {
|
||||
if (
|
||||
it != project
|
||||
&& it.hasProperty("kotlin")
|
||||
&& it.kotlin.sourceSets.any { it.name.contains("commonMain") }
|
||||
) {
|
||||
api it
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<SourceDirectorySet> findSourcesWithName(String... approximateNames) {
|
||||
return parent.subprojects
|
||||
.findAll { it != project && it.hasProperty("kotlin") }
|
||||
.collectMany { it.kotlin.sourceSets }
|
||||
.findAll { sourceSet ->
|
||||
approximateNames.any { nameToFilter ->
|
||||
sourceSet.name.contains(nameToFilter)
|
||||
}
|
||||
}.collect { it.kotlin }
|
||||
}
|
||||
|
||||
tasks.dokkaHtml {
|
||||
dokkaSourceSets {
|
||||
configureEach {
|
||||
skipDeprecated.set(true)
|
||||
|
||||
sourceLink {
|
||||
localDirectory.set(file("./"))
|
||||
remoteUrl.set(new URL("https://github.com/InsanusMokrassar/MicroUtils/blob/master/"))
|
||||
remoteLineSuffix.set("#L")
|
||||
}
|
||||
}
|
||||
|
||||
named("commonMain") {
|
||||
sourceRoots.setFrom(findSourcesWithName("commonMain"))
|
||||
}
|
||||
|
||||
named("jsMain") {
|
||||
sourceRoots.setFrom(findSourcesWithName("jsMain", "commonMain"))
|
||||
}
|
||||
|
||||
named("jvmMain") {
|
||||
sourceRoots.setFrom(findSourcesWithName("jvmMain", "commonMain"))
|
||||
}
|
||||
}
|
||||
}
|
3
dokka/gradle.properties
Normal file
3
dokka/gradle.properties
Normal file
@ -0,0 +1,3 @@
|
||||
dokka_version=1.4.0
|
||||
|
||||
org.gradle.jvmargs=-Xmx1024m
|
@ -5,9 +5,9 @@ kotlin.incremental=true
|
||||
kotlin.incremental.js=true
|
||||
|
||||
kotlin_version=1.4.10
|
||||
kotlin_coroutines_version=1.3.9
|
||||
kotlin_coroutines_version=1.4.0
|
||||
kotlin_serialisation_core_version=1.0.0
|
||||
kotlin_exposed_version=0.27.1
|
||||
kotlin_exposed_version=0.28.1
|
||||
|
||||
ktor_version=1.4.1
|
||||
|
||||
@ -19,4 +19,4 @@ github_release_plugin_version=2.2.12
|
||||
uuidVersion=0.2.2
|
||||
|
||||
group=dev.inmo
|
||||
version=0.2.2
|
||||
version=0.2.3
|
||||
|
@ -16,7 +16,9 @@ String[] includes = [
|
||||
":ktor:server",
|
||||
":ktor:common",
|
||||
":ktor:client",
|
||||
":coroutines"
|
||||
":coroutines",
|
||||
|
||||
":dokka"
|
||||
]
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user