am i mistaken that the `svg` tag doesn't support `path` ? if that's the case how do you do svgs?
a
am i mistaken that the
svg
tag doesn't support
path
? if that's the case how do you do svgs?
tumbleweed 2
t
I'm far from an expert, but might the follwing help you along?
Copy code
fun SVG.path(block: Tag.() -> Unit = {}): Unit {
    PATH(emptyMap, consumer).visit(block)
}

@Suppress("unused")
open class PATH(
    initialAttributes: Map<String, String>,
    override val consumer: TagConsumer<*>
) : HTMLTag(
    tagName = "path",
    consumer = consumer,
    initialAttributes = initialAttributes,
    namespace = null,
    inlineTag = false,
    emptyTag = false
), HtmlBlockInlineTag

fun FlowContent.icon() {
    svg {
        attributes["width"] = "120"
        attributes["height"] = "120"
        attributes["viewBox"] = "0 0 120 120"

        path {
            attributes["d"] = "M10 10 H110 V110 H10 Z"
            attributes["fill"] = "none"
            attributes["stroke"] = "black"
            attributes["stroke-width"] = "4"
        }
    }
}
kotlinx.html doesn't have typesafe support for svg's (at the time), so you have to add it yourself if you want it. I looked at the source code, but I'm not sure that HtmlBlockInlineTag is the superclass/interface you want/need for PATH, however it does seem to work... 😅
Here's a quick improvement:
Copy code
private const val SVG_NS = "<http://www.w3.org/2000/svg>"

fun SVG.path(block: PATH.() -> Unit = {}): Unit {
    PATH(emptyMap(), consumer).visit(block)
}

@Suppress("unused")
open class PATH(
    initialAttributes: Map<String, String>,
    override val consumer: TagConsumer<*>
) : HTMLTag(
    tagName = "path",
    consumer = consumer,
    initialAttributes = initialAttributes,
    namespace = SVG_NS,
    inlineTag = false,
    emptyTag = true,
)

inline var PATH.d: String
    get() = attributes["d"].orEmpty()
    set(value) { attributes["d"] = value }

inline var PATH.fill: String
    get() = attributes["fill"].orEmpty()
    set(value) { attributes["fill"] = value }

inline var PATH.stroke: String
    get() = attributes["stroke"].orEmpty()
    set(value) { attributes["stroke"] = value }

inline var PATH.strokeWidth: String
    get() = attributes["stroke-width"].orEmpty()
    set(value) { attributes["stroke-width"] = value }

inline var SVG.width: String
    get() = attributes["width"].orEmpty()
    set(value) { attributes["width"] = value }

inline var SVG.height: String
    get() = attributes["height"].orEmpty()
    set(value) { attributes["height"] = value }

inline var SVG.viewBox: String
    get() = attributes["viewBox"].orEmpty()
    set(value) { attributes["viewBox"] = value }
Example usage then looks like this:
Copy code
fun FlowContent.icon() {
    svg {
        width = "120"
        height = "120"
        viewBox = "0 0 120 120"

        path {
            d = "M10 10 H110 V110 H10 Z"
            fill = "none"
            stroke = "black"
            strokeWidth = "4"
        }
    }
}
a
Thanks for the help Tim. you gave me an idea. Doing the following lets me use svgs the way I want:
Copy code
fun FlowContent.Locked(classes: String = "size-4") {
    svg(
        classes = classes,
        viewBox = "0 0 24 24",
        fill = "none",
        stroke = "currentColor",
        strokeWidth = "2",
        strokeLinecap = "round",
        strokeLinejoin = "round"
    ) {
        +"""
            <circle cx="12" cy="16" r="1"/><rect x="3" y="10" width="18" height="12" rx="2"/><path d="M7 10V7a5 5 0 0 1 10 0v3"/>
        """.trimIndent()
    }
}

inline fun FlowOrPhrasingContent.svg(
    classes: String? = null,
    viewBox: String? = null,
    fill: String? = null,
    stroke: String? = null,
    strokeWidth: String? = null,
    strokeLinecap: String? = null,
    strokeLinejoin: String? = null,
    width: String? = null,
    height: String? = null,
    crossinline block: SVG.() -> Unit = {},
) = svgInternal(classes) {
    if (viewBox != null) attributes["viewBox"] = viewBox
    if (fill != null) attributes["fill"] = fill
    if (stroke != null) attributes["stroke"] = stroke
    if (strokeWidth != null) attributes["stroke-width"] = strokeWidth
    if (strokeLinecap != null) attributes["stroke-linecap"] = strokeLinecap
    if (strokeLinejoin != null) attributes["stroke-linejoin"] = strokeLinejoin
    if (width != null) attributes["width"] = width
    if (height != null) attributes["height"] = height
    block()
}
I'm ok with copying the path commands as svg. I just copy paste them from svgs anyway, but I hadn't figured out how to bridge that to the dsl
for my use case, having typed path commands doesnt add much
👍 1
svgInternal = kotlin's svg
Copy code
import kotlinx.html.svg as svgInternal