Seskar Save

Kotlin/JS sugar

Project README

CI Status CI Status CI Status Gradle Plugin Portal Maven Central Kotlin

Seskar

Seskar is a Gradle plugin that provides useful additions for Kotlin/JS projects.

Setup

To add Seskar to your project, you need to add the following configuration to your project's build.gradle.kts:

plugins {
    kotlin("multiplatform") version "1.9.24"
    id("io.github.turansky.seskar") version "2.64.0"
}

// browser target
dependencies {
    implementation("io.github.turansky.seskar:seskar-core:2.64.0")
}

React

Conditional rendering

Seskar generates keys for child elements to prevent problems with conditional rendering. As a result, in the following example Content child state won't be reset after showHeader property change.

val App = FC {
    val showHeader = useShowHeader()
    
    if (showHeader) 
        Header() // generated: key = "@rdk/5"
        
    Content()    // generated: key = "@rdk/7"
    Footer()     // generated: key = "@rdk/8"
}

Dependencies

When a project uses the Kotlin/JS compiler, value classes are autoboxed. If a value class is used as a dependency of a React hook (e.g., in useMemo, useState or useEffect), a new class will be created on every rendering pass, which causes infinite re-rendering.

To prevent this, Seskar disables autoboxing for value class dependencies in hooks. It also converts Long values to String.

Seskar supports Duration by default.

Example
value class Count(
    private val value: Int,
)

val Counter = FC {
    val count: Count = useCount()
    
    useEffect(count) {
        println("Count changed: $count")
    }
}
Without plugin
function Counter() { 
    var count = useCount()
    
    useEffect(
        () => {
            println(`Count changed: $count`)
        },
        // AUTOBOXING
        [ new Count(count) ],
    )
}
With plugin
function Counter() { 
    var count = useCount()
    
    useEffect(
        () => {
            println(`Count changed: $count`)
        },
        // NO AUTOBOXING
        [ count ],
    )
}

Unions

AS-IS

Use enum constant as union value

// TypeScript
type Align = 'TOP' | 'LEFT' | 'BOTTOM' | 'RIGHT'
// Kotlin
import seskar.js.JsVirtual

@JsVirtual
sealed external interface Align {
    companion object {
        @JsValue("TOP")
        val TOP: Align

        @JsValue("LEFT")
        val LEFT: Align

        @JsValue("BOTTOM")
        val BOTTOM: Align

        @JsValue("RIGHT")
        val RIGHT: Align
    }
}

println(Align.TOP)  // 'TOP'
println(Align.LEFT) // 'LEFT'

Kebab case

// TypeScript
type LayoutOrientation = 'top-to-bottom' 
    | 'left-to-right'
    | 'bottom-to-top'
    | 'right-to-left'
// Kotlin
import seskar.js.JsVirtual
import seskar.js.JsValue

@JsVirtual
sealed external interface LayoutOrientation {
    companion object {
        @JsValue("top-to-bottom")
        val TOP_TO_BOTTOM: LayoutOrientation

        @JsValue("left-to-right")
        val LEFT_TO_RIGHT: LayoutOrientation

        @JsValue("bottom-to-top")
        val bottomToTop: LayoutOrientation

        @JsValue("right-to-left")
        val rightToLeft: LayoutOrientation
    }
}

Snake case

// TypeScript
type LayoutOrientation = 'top_to_bottom' 
    | 'left_to_right'
    | 'bottom_to_top'
    | 'right_to_left'
// Kotlin
import seskar.js.JsVirtual
import seskar.js.Case

@JsVirtual
sealed external interface LayoutOrientation {
    companion object {
        @JsValue("top_to_bottom")
        val TOP_TO_BOTTOM: LayoutOrientation

        @JsValue("left_to_right")
        val LEFT_TO_RIGHT: LayoutOrientation

        @JsValue("bottom_to_top")
        val bottomToTop: LayoutOrientation

        @JsValue("right_to_left")
        val rightToLeft: LayoutOrientation
    }
}

Custom

Use String or Int constant as union value

String
// TypeScript
type Align = 't' | 'l' | 'b' | 'r'
// Kotlin
import seskar.js.JsVirtual
import seskar.js.JsValue

@JsVirtual
sealed external interface CustomAlign {
    companion object {
        @JsValue("t")
        val TOP: CustomAlign

        @JsValue("l")
        val LEFT: CustomAlign

        @JsValue("b")
        val BOTTOM: CustomAlign

        @JsValue("r")
        val RIGHT: CustomAlign
    }
}

println(CustomAlign.TOP)  // 't'
println(CustomAlign.LEFT) // 'l'
Int
// TypeScript
type GRAPH_ITEM_TYPE_NODE = 1
type GRAPH_ITEM_TYPE_EDGE = 2
type GRAPH_ITEM_TYPE_PORT = 3
type GRAPH_ITEM_TYPE_LABEL = 4

type GraphItemType = GRAPH_ITEM_TYPE_NODE
    | GRAPH_ITEM_TYPE_EDGE
    | GRAPH_ITEM_TYPE_PORT
    | GRAPH_ITEM_TYPE_LABEL
// Kotlin
import seskar.js.JsIntValue
import seskar.js.JsVirtual

@JsVirtual
sealed external interface GraphItemType {
    companion object {
        @JsIntValue(1)
        val NODE: GraphItemType

        @JsIntValue(2)
        val EDGE: GraphItemType

        @JsIntValue(4)
        val PORT: GraphItemType

        @JsIntValue(8)
        val LABEL: GraphItemType
    }
}

println(GraphItemType.EDGE) // 2
println(GraphItemType.PORT) // 4
Open Source Agenda is not affiliated with "Seskar" Project. README Source: turansky/seskar
Stars
43
Open Issues
0
Last Commit
1 day ago
Repository
License

Open Source Agenda Badge

Open Source Agenda Rating