Skip to content

Instantly share code, notes, and snippets.

@Braayy
Created October 15, 2021 17:15
Show Gist options
  • Save Braayy/7335dc3b539c5c43abdade41d93b7840 to your computer and use it in GitHub Desktop.
Save Braayy/7335dc3b539c5c43abdade41d93b7840 to your computer and use it in GitHub Desktop.
A simple way to inject inline svg files at runtime on Compose For Web
import kotlinx.browser.document
import kotlinx.browser.window
import org.jetbrains.compose.web.attributes.AttrsBuilder
import org.w3c.dom.*
import org.w3c.dom.svg.SVGElement
import kotlin.js.Date
enum class SvgIcon(val path: String) {
// Icons goes here
}
private object SvgUidHolder {
private val RANGE = 1..100_000
private val usedUids = mutableListOf<Double>()
fun generateUid(): Double {
var uid = RANGE.random() * Date.now()
while (usedUids.contains(uid)) {
uid = RANGE.random() * Date.now()
}
usedUids.add(uid)
return uid
}
}
fun <T : Element> AttrsBuilder<T>.inlineIcon(icon: SvgIcon) {
ref { element ->
val uid = "inlinesvg-${icon.name.lowercase()}-${SvgUidHolder.generateUid()}"
injectInlineSvgInto(element, uid, icon.path)
onDispose {
element.getElementsByClassName(uid).asList()
.firstOrNull { element is SVGElement }
?.remove()
}
}
}
private fun injectInlineSvgInto(
parent: Element,
id: String,
path: String
) = window.fetch(path).then { it.text() }.then { svgText ->
val template = document.createElement("template") as HTMLTemplateElement
template.innerHTML = svgText
val svgElement = template.content.firstElementChild ?: throw IllegalArgumentException("$path svg content is not valid")
svgElement.classList.add(id)
parent.appendChild(svgElement)
svgElement
}.catch {
console.error("An error occurred while injecting inline svg: ${it.message}")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment