jsMain.styled.sheets.Sheet.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of kotlin-styled-next-js
Show all versions of kotlin-styled-next-js
Kotlin implementation of styled-components
package styled.sheets
import js.core.asList
import web.cssom.CSSStyleSheet
import web.dom.document
import web.html.HTMLStyleElement
internal typealias GroupId = Int
internal const val styleId = "ksc-global-style"
internal const val importStyleId = "$styleId-imports"
internal enum class RuleType { REGULAR, IMPORT }
internal interface Sheet {
/**
* Schedule [rules] for injection into the DOM.
* They will be injected when the [injectScheduled] function is called the next time.
*/
fun scheduleToInject(rules: Iterable): GroupId
fun injectScheduled()
}
internal const val DEFAULT_MAX_RULES_PER_SHEET = 50
/**
* @param maxRulesPerSheet Having too many rules in a stylesheet may result in slow style recalculation, particularly
* when the DOM is complex. This parameter controls how many rules could be inserted into a stylesheet before a new
* stylesheet is created. If [maxRulesPerSheet] is null, all rules will be inserted into a single stylesheet.
*/
internal abstract class AbstractSheet(
private val ruleType: RuleType,
protected val maxRulesPerSheet: Int? = DEFAULT_MAX_RULES_PER_SHEET
) : Sheet {
protected val usedStyleElements = mutableListOf()
private val id: String
get() = when (ruleType) {
RuleType.REGULAR -> styleId
RuleType.IMPORT -> importStyleId
}
private var currentStyleElement: HTMLStyleElement? = null
private var partitionCounter = 0
private fun createStyleElement(): HTMLStyleElement {
val id = when (maxRulesPerSheet) {
null -> id
else -> "${id}_${partitionCounter++}"
}
val style = document.head.appendChild(document.createElement("style")) as HTMLStyleElement
style.setAttribute("id", id)
usedStyleElements += style
return style
}
protected fun getCurrentStyleElement(rulesToAdd: Int): HTMLStyleElement {
val element = currentStyleElement?.takeIf {
it.parentNode != null && (maxRulesPerSheet == null || it.cssSheet.cssRules.length + rulesToAdd <= maxRulesPerSheet)
} ?: createStyleElement().also {
currentStyleElement = it
}
return element
}
protected val HTMLStyleElement.cssSheet: CSSStyleSheet
get() = sheet as CSSStyleSheet
protected fun HTMLStyleElement.removeAndCleanUp() {
remove()
usedStyleElements.remove(this)
if (currentStyleElement == this) {
currentStyleElement = null
}
}
internal open fun clear() {
usedStyleElements.toList().forEach {
it.removeAndCleanUp()
}
document.querySelectorAll(styleElementsSelector(id)).asList().forEach {
(it as HTMLStyleElement).remove()
}
}
}
internal fun styleElementsSelector(id: String) = "[id^='${id}_'],[id='$id']"
© 2015 - 2025 Weber Informatics LLC | Privacy Policy