From 9ff87a3dfdb2e4766c93d4295dbb8ea7aca6d900 Mon Sep 17 00:00:00 2001 From: Vitalii Lipovetskii Date: Mon, 23 Dec 2024 10:27:27 +0200 Subject: [PATCH 01/14] Add DSL to build grid columns with LitRenderer --- .../mvysny/karibudsl/v10/KCssVarNameA.kt | 10 ++ .../v10/KLitRendererAttributesDsl.kt | 51 +++++++ .../mvysny/karibudsl/v10/KLitRendererDsl.kt | 91 +++++++++++ .../karibudsl/v10/KLitRendererTagsDsl.kt | 144 ++++++++++++++++++ .../mvysny/karibudsl/v10/KLitRendererTheme.kt | 14 ++ .../mvysny/karibudsl/v10/KLumoColors.kt | 34 +++++ .../mvysny/karibudsl/v10/KLumoTypography.kt | 36 +++++ 7 files changed, 380 insertions(+) create mode 100644 karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KCssVarNameA.kt create mode 100644 karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererAttributesDsl.kt create mode 100644 karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererDsl.kt create mode 100644 karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererTagsDsl.kt create mode 100644 karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererTheme.kt create mode 100644 karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLumoColors.kt create mode 100644 karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLumoTypography.kt diff --git a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KCssVarNameA.kt b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KCssVarNameA.kt new file mode 100644 index 00000000..60c83415 --- /dev/null +++ b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KCssVarNameA.kt @@ -0,0 +1,10 @@ +package com.github.mvysny.karibudsl.v10 + +/** + * style="line-height: var(--lumo-line-height-m);" + * style="font-size: var(--lumo-font-size-s); color: var(--lumo-secondary-text-color);" + */ +interface KCssVarNameA { + val varName : String + val cssValue get() = "var($varName)" +} \ No newline at end of file diff --git a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererAttributesDsl.kt b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererAttributesDsl.kt new file mode 100644 index 00000000..e1c760fa --- /dev/null +++ b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererAttributesDsl.kt @@ -0,0 +1,51 @@ +package com.github.mvysny.karibudsl.v10 + +import com.vaadin.flow.component.icon.VaadinIcon +import kotlin.apply +import kotlin.collections.asSequence +import kotlin.collections.joinToString +import kotlin.sequences.joinToString +import kotlinx.css.CssBuilder +import kotlinx.css.hyphenize + +data class KLitRendererAttribute( + val name: String, + val value: String +) { + override fun toString() = "$name=\"$value\"" +} + +/** + * style="align-items: center;" + * style="line-height: var(--lumo-line-height-m);" + * style="font-size: var(--lumo-font-size-s); color: var(--lumo-secondary-text-color);" + */ +private fun CssBuilder.buildInlineStyleText() = + declarations.asSequence().joinToString(separator = "; ") { (key, value) -> + "${key.hyphenize()}: $value" + } + +fun KLitRendererTagsBuilderA.style(block: CssBuilder.() -> Unit) = + KLitRendererAttribute("style", CssBuilder().apply(block).buildInlineStyleText()) + +fun KLitRendererTagsBuilderA.theme(vararg names: KLitRendererTheme) = + KLitRendererAttribute("theme", names.joinToString(separator = " ") { it.name }) + +/** + * --- Renderers https://vaadin.com/docs/latest/components/grid/renderers + * "" + */ +fun KLitRendererTagsBuilderA.name(value: KLitRendererBuilderA.Property) = + KLitRendererAttribute("name", value.litItem) + +fun KLitRendererTagsBuilderA.img(value: KLitRendererBuilderA.Property) = + KLitRendererAttribute("img", value.litItem) + +fun KLitRendererTagsBuilderA.href(value: String) = + KLitRendererAttribute("href", value) + +fun KLitRendererTagsBuilderA.href(value: KLitRendererBuilderA.Property) = + KLitRendererAttribute("href", value.litItem) + +fun KLitRendererTagsBuilderA.icon(value: VaadinIcon) = + KLitRendererAttribute("icon", value.create().icon) diff --git a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererDsl.kt b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererDsl.kt new file mode 100644 index 00000000..218811b6 --- /dev/null +++ b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererDsl.kt @@ -0,0 +1,91 @@ +package com.github.mvysny.karibudsl.v10 + +import com.github.mvysny.karibudsl.v10.VaadinDsl +import com.vaadin.flow.data.renderer.LitRenderer +import com.github.mvysny.karibudsl.v10.KLitRendererBuilderA.Property +import kotlin.also +import kotlin.apply +import kotlin.collections.forEach +import kotlin.collections.set +import kotlin.text.trimIndent + + +/** + * PRB: \${item.itemName} -> isn't interpreted by [LitRenderer] + * FAIL: $\{item.itemName} + * --- Templates escaping in Kotlin multiline strings https://stackoverflow.com/questions/32993586/templates-escaping-in-kotlin-multiline-strings + * Solution: ${ "\${item.itemName}" } + */ +val String.litItem get() = "\${item.$this}" + +@Suppress("unused") +@VaadinDsl +interface KLitRendererBuilderA { + + data class Property( + val name: String, + val provider: (TSource) -> String, + ) { + val litItem get() = name.litItem + } + + operator fun String.invoke(provider: (TSource) -> String): Property + + fun templateExpression(templateExpression: String) + + fun templateExpression(initBlock: KLitRendererTagsBuilderA.() -> Unit) + +} + +/** + * --- Renderers https://vaadin.com/docs/latest/components/grid/renderers + * --- Display LitRenderer grid cell button as a link in Vaadin 24 https://stackoverflow.com/questions/76984432/display-litrenderer-grid-cell-button-as-a-link-in-vaadin-24 + * --- Vaadin LitRenderer bean exposure to the client https://stackoverflow.com/questions/73101886/vaadin-litrenderer-bean-exposure-to-the-client + * --- How do I implement different row height in a grid - Vaadin Cookbook https://cookbook.vaadin.com/grid-row-height + * --- Dynamically render an image using LitRenderer https://cookbook.vaadin.com/dynamically-render-an-image-using-litrenderer + */ +class KLitRendererBuilder() : KLitRendererBuilderA { + + private var templateExpression = "" + + private val properties = mutableMapOf String>() + + override fun templateExpression(templateExpression: String) { + this.templateExpression = templateExpression.trimIndent() + } + + override fun templateExpression(initBlock: KLitRendererTagsBuilderA.() -> Unit) = + templateExpression(KLitRendererTagsBuilder(this).apply(initBlock).toString()) + + val litRenderer: LitRenderer + get() = + LitRenderer.of(templateExpression).apply { + properties.forEach { (name, provider) -> + withProperty(name, provider) + } + } + + + override fun String.invoke(provider: (TSource) -> String) = + Property( + name = this, + provider = provider, + ).also { + properties[it.name] = provider + } + + fun propertyName(property : Property) : String { + + val provider = properties[property.name] + require(provider != null) { "${property.name} !in ${properties.keys}" } + + return property.litItem + } + +} + +@Suppress("unused") +fun buildLitRenderer( + initBlock: KLitRendererBuilderA.() -> Unit +): LitRenderer = + KLitRendererBuilder().apply(initBlock).litRenderer diff --git a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererTagsDsl.kt b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererTagsDsl.kt new file mode 100644 index 00000000..371bd3a4 --- /dev/null +++ b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererTagsDsl.kt @@ -0,0 +1,144 @@ +package com.github.mvysny.karibudsl.v10 + +import com.github.mvysny.karibudsl.v10.VaadinDsl +import com.github.mvysny.karibudsl.v10.KLitRendererBuilderA.Property +import kotlin.apply +import kotlin.collections.asSequence +import kotlin.collections.joinToString +import kotlin.sequences.joinToString +import kotlin.text.isNotEmpty +import kotlin.text.trimIndent + +@VaadinDsl +interface KLitRendererTagsBuilderA { + + operator fun Property.unaryPlus() + + operator fun String.unaryPlus() + + val spacing get() = KLitRendererTheme.spacing + val padding get() = KLitRendererTheme.padding + + fun horizontalLayout( + vararg attributes: KLitRendererAttribute, + block: KLitRendererTagsBuilderA.() -> Unit + ) + + fun verticalLayout( + vararg attributes: KLitRendererAttribute, + block: KLitRendererTagsBuilderA.() -> Unit + ) + + fun span( + vararg attributes: KLitRendererAttribute, + block: KLitRendererTagsBuilderA.() -> Unit + ) + + fun div( + vararg attributes: KLitRendererAttribute, + block: KLitRendererTagsBuilderA.() -> Unit + ) + + fun anchor( + vararg attributes: KLitRendererAttribute, + block: KLitRendererTagsBuilderA.() -> Unit + ) + + fun vaadinIcon( + vararg attributes: KLitRendererAttribute, + block: KLitRendererTagsBuilderA.() -> Unit + ) +} + +class KLitRendererTagsBuilder( + + private val litRendererBuilder: KLitRendererBuilderA, + + private val tagName: String = "", + private val attributes: String = "", + private val propertyName: String = "", +) : + KLitRendererTagsBuilderA { + + private val children = mutableListOf>() + + override fun toString(): String { + + return when { + tagName.isNotEmpty() -> """ + <$tagName $attributes> + ${children.joinToString(separator = "")} + + """.trimIndent() + + propertyName.isNotEmpty() -> propertyName + + else -> children.joinToString(separator = "") + } + + } + + override fun Property.unaryPlus() { + children.add( + KLitRendererTagsBuilder( + litRendererBuilder, + propertyName = (litRendererBuilder as KLitRendererBuilder).propertyName(this) + ) + ) + } + + override fun String.unaryPlus() { + children.add( + KLitRendererTagsBuilder( + litRendererBuilder, + propertyName = this + ) + ) + } + + private fun addTag( + tagName: String, + attributes: Sequence, + block: KLitRendererTagsBuilderA.() -> Unit + ) { + children.add( + KLitRendererTagsBuilder( + litRendererBuilder, + tagName, + attributes.joinToString(separator = " ") + ).apply(block) + ) + } + + override fun horizontalLayout( + vararg attributes: KLitRendererAttribute, + block: KLitRendererTagsBuilderA.() -> Unit + ) = addTag("vaadin-horizontal-layout", attributes.asSequence(), block) + + override fun verticalLayout( + vararg attributes: KLitRendererAttribute, + block: KLitRendererTagsBuilderA.() -> Unit + ) = addTag("vaadin-vertical-layout", attributes.asSequence(), block) + + override fun span( + vararg attributes: KLitRendererAttribute, + block: KLitRendererTagsBuilderA.() -> Unit + ) = addTag("span", attributes.asSequence(), block) + + override fun div( + vararg attributes: KLitRendererAttribute, + block: KLitRendererTagsBuilderA.() -> Unit + ) = addTag("div", attributes.asSequence(), block) + + override fun anchor( + vararg attributes: KLitRendererAttribute, + block: KLitRendererTagsBuilderA.() -> Unit + ) = addTag("a", attributes.asSequence(), block) + + override fun vaadinIcon( + vararg attributes: KLitRendererAttribute, + block: KLitRendererTagsBuilderA.() -> Unit + ) = addTag("vaadin-icon", attributes.asSequence(), block) + +} + diff --git a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererTheme.kt b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererTheme.kt new file mode 100644 index 00000000..3dac8f38 --- /dev/null +++ b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererTheme.kt @@ -0,0 +1,14 @@ +package com.github.mvysny.karibudsl.v10 + +/** + * --- Renderers https://vaadin.com/docs/latest/components/grid/renderers + * "" + * --- Vaadin 23 - CSS Remove theme=“padding spacing” https://vaadin.com/forum/t/vaadin-23-css-remove-theme-padding-spacing/167207 + * The CSS and the HTML produced are the same comparing old to new, but for some reason, the theme=“padding spacing” is now causing issues. + */ +@Suppress("EnumEntryName") +enum class KLitRendererTheme { + spacing, + padding, + ; +} \ No newline at end of file diff --git a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLumoColors.kt b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLumoColors.kt new file mode 100644 index 00000000..b9567444 --- /dev/null +++ b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLumoColors.kt @@ -0,0 +1,34 @@ +package com.github.mvysny.karibudsl.v10 + +import kotlinx.css.Color + +/** + * --- Lumo Colors https://vaadin.com/docs/latest/styling/lumo/lumo-style-properties/color + */ +@Suppress("unused", "EnumEntryName") +enum class KLumoPrimaryColor(override val varName: String) : KCssVarNameA { + `10pct`("--lumo-primary-color-10pct"), + `50pct`("--lumo-primary-color-50pct"), + `100pct`("--lumo-primary-color"), + Text("--lumo-primary-text-color"), + Contrast("--lumo-primary-contrast-color"), + + ; + + operator fun unaryPlus() = Color(cssValue) + +} + +@Suppress("unused") +enum class KLumoTextColor(override val varName: String) : KCssVarNameA { + Heading("--lumo-header-text-color"), + Body("--lumo-body-text-color"), + Secondary("--lumo-secondary-text-color"), + Tertiary("--lumo-tertiary-text-color"), + Disabled("--lumo-disabled-text-color"), + + ; + + operator fun unaryPlus() = Color(cssValue) + +} diff --git a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLumoTypography.kt b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLumoTypography.kt new file mode 100644 index 00000000..0bcf12dc --- /dev/null +++ b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLumoTypography.kt @@ -0,0 +1,36 @@ +package com.github.mvysny.karibudsl.v10 + +import kotlinx.css.LinearDimension +import kotlinx.css.properties.LineHeight + +/** + * --- Lumo Typography https://vaadin.com/docs/latest/styling/lumo/lumo-style-properties/typography + */ +@Suppress("unused", "SpellCheckingInspection") +enum class KLumoFontSize(override val varName: String) : KCssVarNameA { + XXXL("--lumo-font-size-xxxl"), + XXL("--lumo-font-size-xxl"), + XL("--lumo-font-size-xl"), + L("--lumo-font-size-l"), + M("--lumo-font-size-m"), + S("--lumo-font-size-s"), + XS("--lumo-font-size-xs"), + XXS("--lumo-font-size-xxs"), + + ; + + operator fun unaryPlus() = LinearDimension(cssValue) + +} + +@Suppress("unused") +enum class KLumoLineHeight(override val varName: String) : KCssVarNameA { + M("--lumo-line-height-m"), + S("--lumo-line-height-s"), + XS("--lumo-line-height-xs"), + ; + + operator fun unaryPlus() = LineHeight(cssValue) + +} + From ae3f55cacc09464a1a6ff90b296bf99629225575 Mon Sep 17 00:00:00 2001 From: Vitalii Lipovetskii Date: Mon, 23 Dec 2024 10:50:41 +0200 Subject: [PATCH 02/14] Fixes to support Explicit API Mode --- .../mvysny/karibudsl/v10/KCssVarNameA.kt | 6 +-- .../v10/KLitRendererAttributesDsl.kt | 18 +++---- .../mvysny/karibudsl/v10/KLitRendererDsl.kt | 25 +++++----- .../karibudsl/v10/KLitRendererTagsDsl.kt | 48 ++++++++++++------- .../mvysny/karibudsl/v10/KLumoColors.kt | 8 ++-- .../mvysny/karibudsl/v10/KLumoTypography.kt | 8 ++-- 6 files changed, 63 insertions(+), 50 deletions(-) diff --git a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KCssVarNameA.kt b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KCssVarNameA.kt index 60c83415..f97ee81a 100644 --- a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KCssVarNameA.kt +++ b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KCssVarNameA.kt @@ -4,7 +4,7 @@ package com.github.mvysny.karibudsl.v10 * style="line-height: var(--lumo-line-height-m);" * style="font-size: var(--lumo-font-size-s); color: var(--lumo-secondary-text-color);" */ -interface KCssVarNameA { - val varName : String - val cssValue get() = "var($varName)" +public interface KCssVarNameA { + public val varName : String + public val cssValue get() = "var($varName)" } \ No newline at end of file diff --git a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererAttributesDsl.kt b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererAttributesDsl.kt index e1c760fa..7bdc7a50 100644 --- a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererAttributesDsl.kt +++ b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererAttributesDsl.kt @@ -8,11 +8,11 @@ import kotlin.sequences.joinToString import kotlinx.css.CssBuilder import kotlinx.css.hyphenize -data class KLitRendererAttribute( +public data class KLitRendererAttribute( val name: String, val value: String ) { - override fun toString() = "$name=\"$value\"" + override fun toString(): String = "$name=\"$value\"" } /** @@ -25,27 +25,27 @@ private fun CssBuilder.buildInlineStyleText() = "${key.hyphenize()}: $value" } -fun KLitRendererTagsBuilderA.style(block: CssBuilder.() -> Unit) = +public fun KLitRendererTagsBuilderA.style(block: CssBuilder.() -> Unit) = KLitRendererAttribute("style", CssBuilder().apply(block).buildInlineStyleText()) -fun KLitRendererTagsBuilderA.theme(vararg names: KLitRendererTheme) = +public fun KLitRendererTagsBuilderA.theme(vararg names: KLitRendererTheme) = KLitRendererAttribute("theme", names.joinToString(separator = " ") { it.name }) /** * --- Renderers https://vaadin.com/docs/latest/components/grid/renderers * "" */ -fun KLitRendererTagsBuilderA.name(value: KLitRendererBuilderA.Property) = +public fun KLitRendererTagsBuilderA.name(value: KLitRendererBuilderA.Property) = KLitRendererAttribute("name", value.litItem) -fun KLitRendererTagsBuilderA.img(value: KLitRendererBuilderA.Property) = +public fun KLitRendererTagsBuilderA.img(value: KLitRendererBuilderA.Property) = KLitRendererAttribute("img", value.litItem) -fun KLitRendererTagsBuilderA.href(value: String) = +public fun KLitRendererTagsBuilderA.href(value: String) = KLitRendererAttribute("href", value) -fun KLitRendererTagsBuilderA.href(value: KLitRendererBuilderA.Property) = +public fun KLitRendererTagsBuilderA.href(value: KLitRendererBuilderA.Property) = KLitRendererAttribute("href", value.litItem) -fun KLitRendererTagsBuilderA.icon(value: VaadinIcon) = +public fun KLitRendererTagsBuilderA.icon(value: VaadinIcon) = KLitRendererAttribute("icon", value.create().icon) diff --git a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererDsl.kt b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererDsl.kt index 218811b6..b237b54a 100644 --- a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererDsl.kt +++ b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererDsl.kt @@ -16,24 +16,24 @@ import kotlin.text.trimIndent * --- Templates escaping in Kotlin multiline strings https://stackoverflow.com/questions/32993586/templates-escaping-in-kotlin-multiline-strings * Solution: ${ "\${item.itemName}" } */ -val String.litItem get() = "\${item.$this}" +public val String.litItem get() = "\${item.$this}" @Suppress("unused") @VaadinDsl -interface KLitRendererBuilderA { +public interface KLitRendererBuilderA { - data class Property( + public data class Property( val name: String, val provider: (TSource) -> String, ) { - val litItem get() = name.litItem + public val litItem get() = name.litItem } - operator fun String.invoke(provider: (TSource) -> String): Property + public operator fun String.invoke(provider: (TSource) -> String): Property - fun templateExpression(templateExpression: String) + public fun templateExpression(templateExpression: String) - fun templateExpression(initBlock: KLitRendererTagsBuilderA.() -> Unit) + public fun templateExpression(initBlock: KLitRendererTagsBuilderA.() -> Unit) } @@ -44,7 +44,7 @@ interface KLitRendererBuilderA { * --- How do I implement different row height in a grid - Vaadin Cookbook https://cookbook.vaadin.com/grid-row-height * --- Dynamically render an image using LitRenderer https://cookbook.vaadin.com/dynamically-render-an-image-using-litrenderer */ -class KLitRendererBuilder() : KLitRendererBuilderA { +public class KLitRendererBuilder() : KLitRendererBuilderA { private var templateExpression = "" @@ -54,10 +54,11 @@ class KLitRendererBuilder() : KLitRendererBuilderA { this.templateExpression = templateExpression.trimIndent() } - override fun templateExpression(initBlock: KLitRendererTagsBuilderA.() -> Unit) = + override fun templateExpression(initBlock: KLitRendererTagsBuilderA.() -> Unit) { templateExpression(KLitRendererTagsBuilder(this).apply(initBlock).toString()) + } - val litRenderer: LitRenderer + public val litRenderer: LitRenderer get() = LitRenderer.of(templateExpression).apply { properties.forEach { (name, provider) -> @@ -74,7 +75,7 @@ class KLitRendererBuilder() : KLitRendererBuilderA { properties[it.name] = provider } - fun propertyName(property : Property) : String { + public fun propertyName(property : Property) : String { val provider = properties[property.name] require(provider != null) { "${property.name} !in ${properties.keys}" } @@ -85,7 +86,7 @@ class KLitRendererBuilder() : KLitRendererBuilderA { } @Suppress("unused") -fun buildLitRenderer( +public fun buildLitRenderer( initBlock: KLitRendererBuilderA.() -> Unit ): LitRenderer = KLitRendererBuilder().apply(initBlock).litRenderer diff --git a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererTagsDsl.kt b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererTagsDsl.kt index 371bd3a4..f384235a 100644 --- a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererTagsDsl.kt +++ b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererTagsDsl.kt @@ -10,47 +10,47 @@ import kotlin.text.isNotEmpty import kotlin.text.trimIndent @VaadinDsl -interface KLitRendererTagsBuilderA { +public interface KLitRendererTagsBuilderA { - operator fun Property.unaryPlus() + public operator fun Property.unaryPlus() - operator fun String.unaryPlus() + public operator fun String.unaryPlus() - val spacing get() = KLitRendererTheme.spacing - val padding get() = KLitRendererTheme.padding + public val spacing: KLitRendererTheme get() = KLitRendererTheme.spacing + public val padding: KLitRendererTheme get() = KLitRendererTheme.padding - fun horizontalLayout( + public fun horizontalLayout( vararg attributes: KLitRendererAttribute, block: KLitRendererTagsBuilderA.() -> Unit ) - fun verticalLayout( + public fun verticalLayout( vararg attributes: KLitRendererAttribute, block: KLitRendererTagsBuilderA.() -> Unit ) - fun span( + public fun span( vararg attributes: KLitRendererAttribute, block: KLitRendererTagsBuilderA.() -> Unit ) - fun div( + public fun div( vararg attributes: KLitRendererAttribute, block: KLitRendererTagsBuilderA.() -> Unit ) - fun anchor( + public fun anchor( vararg attributes: KLitRendererAttribute, block: KLitRendererTagsBuilderA.() -> Unit ) - fun vaadinIcon( + public fun vaadinIcon( vararg attributes: KLitRendererAttribute, block: KLitRendererTagsBuilderA.() -> Unit ) } -class KLitRendererTagsBuilder( +public class KLitRendererTagsBuilder( private val litRendererBuilder: KLitRendererBuilderA, @@ -113,32 +113,44 @@ class KLitRendererTagsBuilder( override fun horizontalLayout( vararg attributes: KLitRendererAttribute, block: KLitRendererTagsBuilderA.() -> Unit - ) = addTag("vaadin-horizontal-layout", attributes.asSequence(), block) + ) { + addTag("vaadin-horizontal-layout", attributes.asSequence(), block) + } override fun verticalLayout( vararg attributes: KLitRendererAttribute, block: KLitRendererTagsBuilderA.() -> Unit - ) = addTag("vaadin-vertical-layout", attributes.asSequence(), block) + ) { + addTag("vaadin-vertical-layout", attributes.asSequence(), block) + } override fun span( vararg attributes: KLitRendererAttribute, block: KLitRendererTagsBuilderA.() -> Unit - ) = addTag("span", attributes.asSequence(), block) + ) { + addTag("span", attributes.asSequence(), block) + } override fun div( vararg attributes: KLitRendererAttribute, block: KLitRendererTagsBuilderA.() -> Unit - ) = addTag("div", attributes.asSequence(), block) + ) { + addTag("div", attributes.asSequence(), block) + } override fun anchor( vararg attributes: KLitRendererAttribute, block: KLitRendererTagsBuilderA.() -> Unit - ) = addTag("a", attributes.asSequence(), block) + ) { + addTag("a", attributes.asSequence(), block) + } override fun vaadinIcon( vararg attributes: KLitRendererAttribute, block: KLitRendererTagsBuilderA.() -> Unit - ) = addTag("vaadin-icon", attributes.asSequence(), block) + ) { + addTag("vaadin-icon", attributes.asSequence(), block) + } } diff --git a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLumoColors.kt b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLumoColors.kt index b9567444..b189e8d3 100644 --- a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLumoColors.kt +++ b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLumoColors.kt @@ -6,7 +6,7 @@ import kotlinx.css.Color * --- Lumo Colors https://vaadin.com/docs/latest/styling/lumo/lumo-style-properties/color */ @Suppress("unused", "EnumEntryName") -enum class KLumoPrimaryColor(override val varName: String) : KCssVarNameA { +public enum class KLumoPrimaryColor(override val varName: String) : KCssVarNameA { `10pct`("--lumo-primary-color-10pct"), `50pct`("--lumo-primary-color-50pct"), `100pct`("--lumo-primary-color"), @@ -15,12 +15,12 @@ enum class KLumoPrimaryColor(override val varName: String) : KCssVarNameA { ; - operator fun unaryPlus() = Color(cssValue) + public operator fun unaryPlus(): Color = Color(cssValue) } @Suppress("unused") -enum class KLumoTextColor(override val varName: String) : KCssVarNameA { +public enum class KLumoTextColor(override val varName: String) : KCssVarNameA { Heading("--lumo-header-text-color"), Body("--lumo-body-text-color"), Secondary("--lumo-secondary-text-color"), @@ -29,6 +29,6 @@ enum class KLumoTextColor(override val varName: String) : KCssVarNameA { ; - operator fun unaryPlus() = Color(cssValue) + public operator fun unaryPlus(): Color = Color(cssValue) } diff --git a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLumoTypography.kt b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLumoTypography.kt index 0bcf12dc..80e226bc 100644 --- a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLumoTypography.kt +++ b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLumoTypography.kt @@ -7,7 +7,7 @@ import kotlinx.css.properties.LineHeight * --- Lumo Typography https://vaadin.com/docs/latest/styling/lumo/lumo-style-properties/typography */ @Suppress("unused", "SpellCheckingInspection") -enum class KLumoFontSize(override val varName: String) : KCssVarNameA { +public enum class KLumoFontSize(override val varName: String) : KCssVarNameA { XXXL("--lumo-font-size-xxxl"), XXL("--lumo-font-size-xxl"), XL("--lumo-font-size-xl"), @@ -19,18 +19,18 @@ enum class KLumoFontSize(override val varName: String) : KCssVarNameA { ; - operator fun unaryPlus() = LinearDimension(cssValue) + public operator fun unaryPlus(): LinearDimension = LinearDimension(cssValue) } @Suppress("unused") -enum class KLumoLineHeight(override val varName: String) : KCssVarNameA { +public enum class KLumoLineHeight(override val varName: String) : KCssVarNameA { M("--lumo-line-height-m"), S("--lumo-line-height-s"), XS("--lumo-line-height-xs"), ; - operator fun unaryPlus() = LineHeight(cssValue) + public operator fun unaryPlus(): LineHeight = LineHeight(cssValue) } From 6b63b5032ee8913ecdb53a6af180c91e01cb4ce6 Mon Sep 17 00:00:00 2001 From: Vitalii Lipovetskii Date: Mon, 23 Dec 2024 10:53:54 +0200 Subject: [PATCH 03/14] More fixes to support Explicit API Mode () --- .../main/kotlin/com/github/mvysny/karibudsl/v10/KCssVarNameA.kt | 2 +- .../kotlin/com/github/mvysny/karibudsl/v10/KLitRendererDsl.kt | 2 +- .../kotlin/com/github/mvysny/karibudsl/v10/KLitRendererTheme.kt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KCssVarNameA.kt b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KCssVarNameA.kt index f97ee81a..00f39fe2 100644 --- a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KCssVarNameA.kt +++ b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KCssVarNameA.kt @@ -6,5 +6,5 @@ package com.github.mvysny.karibudsl.v10 */ public interface KCssVarNameA { public val varName : String - public val cssValue get() = "var($varName)" + public val cssValue: String get() = "var($varName)" } \ No newline at end of file diff --git a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererDsl.kt b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererDsl.kt index b237b54a..4b0e5f99 100644 --- a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererDsl.kt +++ b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererDsl.kt @@ -26,7 +26,7 @@ public interface KLitRendererBuilderA { val name: String, val provider: (TSource) -> String, ) { - public val litItem get() = name.litItem + public val litItem: String get() = name.litItem } public operator fun String.invoke(provider: (TSource) -> String): Property diff --git a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererTheme.kt b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererTheme.kt index 3dac8f38..b8ad0618 100644 --- a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererTheme.kt +++ b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererTheme.kt @@ -7,7 +7,7 @@ package com.github.mvysny.karibudsl.v10 * The CSS and the HTML produced are the same comparing old to new, but for some reason, the theme=“padding spacing” is now causing issues. */ @Suppress("EnumEntryName") -enum class KLitRendererTheme { +public enum class KLitRendererTheme { spacing, padding, ; From 6823b5e932bc1199b256c741ee5c569dd3d2a5d6 Mon Sep 17 00:00:00 2001 From: Vitalii Lipovetskii Date: Fri, 10 Jan 2025 14:35:56 +0200 Subject: [PATCH 04/14] Added: KLitRendererTagsBuilderA.style() KLitRendererTagsBuilderA.src() KLitRendererTagsBuilderA.img() private val selfClosing: Boolean = false --- .../v10/KLitRendererAttributesDsl.kt | 14 ++++-- .../mvysny/karibudsl/v10/KLitRendererDsl.kt | 8 +--- .../karibudsl/v10/KLitRendererTagsDsl.kt | 48 +++++++++++++++---- 3 files changed, 49 insertions(+), 21 deletions(-) diff --git a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererAttributesDsl.kt b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererAttributesDsl.kt index 7bdc7a50..16838fb1 100644 --- a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererAttributesDsl.kt +++ b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererAttributesDsl.kt @@ -1,10 +1,6 @@ package com.github.mvysny.karibudsl.v10 import com.vaadin.flow.component.icon.VaadinIcon -import kotlin.apply -import kotlin.collections.asSequence -import kotlin.collections.joinToString -import kotlin.sequences.joinToString import kotlinx.css.CssBuilder import kotlinx.css.hyphenize @@ -25,6 +21,9 @@ private fun CssBuilder.buildInlineStyleText() = "${key.hyphenize()}: $value" } +public fun KLitRendererTagsBuilderA.style(value: String) = + KLitRendererAttribute("style", value) + public fun KLitRendererTagsBuilderA.style(block: CssBuilder.() -> Unit) = KLitRendererAttribute("style", CssBuilder().apply(block).buildInlineStyleText()) @@ -38,6 +37,13 @@ public fun KLitRendererTagsBuilderA.theme(vararg names: KLitR public fun KLitRendererTagsBuilderA.name(value: KLitRendererBuilderA.Property) = KLitRendererAttribute("name", value.litItem) +/** + * "" + * "
${item.name}
" + */ +public fun KLitRendererTagsBuilderA.src(value: KLitRendererBuilderA.Property) = + KLitRendererAttribute("src", value.litItem) + public fun KLitRendererTagsBuilderA.img(value: KLitRendererBuilderA.Property) = KLitRendererAttribute("img", value.litItem) diff --git a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererDsl.kt b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererDsl.kt index 4b0e5f99..8cec7d7d 100644 --- a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererDsl.kt +++ b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererDsl.kt @@ -1,13 +1,7 @@ package com.github.mvysny.karibudsl.v10 -import com.github.mvysny.karibudsl.v10.VaadinDsl -import com.vaadin.flow.data.renderer.LitRenderer import com.github.mvysny.karibudsl.v10.KLitRendererBuilderA.Property -import kotlin.also -import kotlin.apply -import kotlin.collections.forEach -import kotlin.collections.set -import kotlin.text.trimIndent +import com.vaadin.flow.data.renderer.LitRenderer /** diff --git a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererTagsDsl.kt b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererTagsDsl.kt index f384235a..89d0687e 100644 --- a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererTagsDsl.kt +++ b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererTagsDsl.kt @@ -1,13 +1,6 @@ package com.github.mvysny.karibudsl.v10 -import com.github.mvysny.karibudsl.v10.VaadinDsl import com.github.mvysny.karibudsl.v10.KLitRendererBuilderA.Property -import kotlin.apply -import kotlin.collections.asSequence -import kotlin.collections.joinToString -import kotlin.sequences.joinToString -import kotlin.text.isNotEmpty -import kotlin.text.trimIndent @VaadinDsl public interface KLitRendererTagsBuilderA { @@ -48,6 +41,11 @@ public interface KLitRendererTagsBuilderA { vararg attributes: KLitRendererAttribute, block: KLitRendererTagsBuilderA.() -> Unit ) + + public fun img( + vararg attributes: KLitRendererAttribute, + ) + } public class KLitRendererTagsBuilder( @@ -57,6 +55,11 @@ public class KLitRendererTagsBuilder( private val tagName: String = "", private val attributes: String = "", private val propertyName: String = "", + + /** + * --- What are Self Closing Tags in HTML? https://www.scaler.com/topics/self-closing-tags-in-html/ + */ + private val selfClosing: Boolean = false, ) : KLitRendererTagsBuilderA { @@ -65,11 +68,17 @@ public class KLitRendererTagsBuilder( override fun toString(): String { return when { - tagName.isNotEmpty() -> """ + tagName.isNotEmpty() -> + if (!selfClosing) + """ <$tagName $attributes> ${children.joinToString(separator = "")} """.trimIndent() + else + """ + <$tagName $attributes /> + """.trimIndent() propertyName.isNotEmpty() -> propertyName @@ -99,13 +108,15 @@ public class KLitRendererTagsBuilder( private fun addTag( tagName: String, attributes: Sequence, - block: KLitRendererTagsBuilderA.() -> Unit + block: KLitRendererTagsBuilderA.() -> Unit, + selfClosing: Boolean = false, ) { children.add( KLitRendererTagsBuilder( litRendererBuilder, tagName, - attributes.joinToString(separator = " ") + attributes.joinToString(separator = " "), + selfClosing = selfClosing ).apply(block) ) } @@ -152,5 +163,22 @@ public class KLitRendererTagsBuilder( addTag("vaadin-icon", attributes.asSequence(), block) } + /** + * "" + * "
${item.name}
" + * + * [selfClosing] = true + * --- The Image Tag https://www.understandingcode.com/image-tag + * The Tag + * This tag is different from other tags, in that it has no closing tag. + * It is called a self-closing tag, which means that there is just a slash at the end of the opening tag (ex. ) + * --- img tag and / and a lie https://www.codecademy.com/forum_questions/5236c2c9f10c607ef4000bc0 + */ + override fun img( + vararg attributes: KLitRendererAttribute, + ) { + addTag("img", attributes.asSequence(), { }, selfClosing = true) + } + } From d85ee7e3197aee25b59880bcb7b820688d203699 Mon Sep 17 00:00:00 2001 From: Vitalii Lipovetskii Date: Fri, 10 Jan 2025 15:25:32 +0200 Subject: [PATCH 05/14] + CategoriesLit --- .../starter/beveragebuddy/ui/MainLayout.kt | 5 + .../ui/categories/CategoriesListLit.kt | 136 ++++++++++++++++++ 2 files changed, 141 insertions(+) create mode 100644 example/src/main/kotlin/com/vaadin/starter/beveragebuddy/ui/categories/CategoriesListLit.kt diff --git a/example/src/main/kotlin/com/vaadin/starter/beveragebuddy/ui/MainLayout.kt b/example/src/main/kotlin/com/vaadin/starter/beveragebuddy/ui/MainLayout.kt index 50fe86f4..239ad51c 100644 --- a/example/src/main/kotlin/com/vaadin/starter/beveragebuddy/ui/MainLayout.kt +++ b/example/src/main/kotlin/com/vaadin/starter/beveragebuddy/ui/MainLayout.kt @@ -23,6 +23,7 @@ import com.vaadin.flow.component.orderedlayout.VerticalLayout import com.vaadin.flow.router.HighlightConditions import com.vaadin.flow.router.RouterLayout import com.vaadin.starter.beveragebuddy.ui.categories.CategoriesList +import com.vaadin.starter.beveragebuddy.ui.categories.CategoriesListLit import com.vaadin.starter.beveragebuddy.ui.reviews.ReviewsList /** @@ -47,6 +48,10 @@ class MainLayout : KComposite(), RouterLayout { addClassName("main-layout__nav-item") highlightCondition = HighlightConditions.sameLocation() } + routerLink(VaadinIcon.ARCHIVES, "Categories-lit", CategoriesListLit::class) { + addClassName("main-layout__nav-item") + highlightCondition = HighlightConditions.sameLocation() + } } } } diff --git a/example/src/main/kotlin/com/vaadin/starter/beveragebuddy/ui/categories/CategoriesListLit.kt b/example/src/main/kotlin/com/vaadin/starter/beveragebuddy/ui/categories/CategoriesListLit.kt new file mode 100644 index 00000000..abee1d16 --- /dev/null +++ b/example/src/main/kotlin/com/vaadin/starter/beveragebuddy/ui/categories/CategoriesListLit.kt @@ -0,0 +1,136 @@ +/* + * Copyright 2000-2017 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.starter.beveragebuddy.ui.categories + +import com.github.mvysny.karibudsl.v10.* +import com.github.mvysny.kaributools.ModifierKey.Alt +import com.github.mvysny.kaributools.addShortcut +import com.vaadin.flow.component.Key.KEY_E +import com.vaadin.flow.component.button.Button +import com.vaadin.flow.component.button.ButtonVariant +import com.vaadin.flow.component.grid.Grid +import com.vaadin.flow.component.grid.contextmenu.GridContextMenu +import com.vaadin.flow.component.html.H3 +import com.vaadin.flow.component.icon.Icon +import com.vaadin.flow.component.icon.VaadinIcon +import com.vaadin.flow.component.notification.Notification +import com.vaadin.flow.router.PageTitle +import com.vaadin.flow.router.Route +import com.vaadin.starter.beveragebuddy.backend.Category +import com.vaadin.starter.beveragebuddy.backend.CategoryService +import com.vaadin.starter.beveragebuddy.backend.ReviewService +import com.vaadin.starter.beveragebuddy.ui.MainLayout +import com.vaadin.starter.beveragebuddy.ui.Toolbar +import com.vaadin.starter.beveragebuddy.ui.toolbarView + +/** + * Displays the list of available categories, with a search filter as well as + * buttons to add a new category or edit existing ones. + */ +@Route(value = "categories-lit", layout = MainLayout::class) +@PageTitle("Categories List") +class CategoriesListLit : KComposite() { + + private lateinit var header: H3 + private lateinit var toolbar: Toolbar + private lateinit var grid: Grid + // can't retrieve GridContextMenu from Grid: https://github.com/vaadin/vaadin-grid-flow/issues/523 + lateinit var gridContextMenu: GridContextMenu + private set + + private val editorDialog = CategoryEditorDialog( + { category -> saveCategory(category) }, + { deleteCategory(it) }) + + private val root = ui { + verticalLayout(false) { + content { align(stretch, top) } + toolbar = toolbarView("New category") { + onSearch = { updateView() } + onCreate = { editorDialog.createNew() } + } + header = h3() + grid = grid { + isExpand = true + + columnFor(Category::name) { + setHeader("Category") + } + column({ it.getReviewCount() }) { + setHeader("Beverages") + } + componentColumn({ cat -> createEditButton(cat) }) { + flexGrow = 0; key = "edit" + } + + gridContextMenu = gridContextMenu { + item("New", { editorDialog.createNew() }) + item("Edit (Alt+E)", { cat -> if (cat != null) edit(cat) }) + item("Delete", { cat -> if (cat != null) deleteCategory(cat) }) + } + } + + addShortcut(Alt + KEY_E) { + val category: Category? = grid.asSingleSelect().value + if (category != null) { + edit(category) + } + } + } + } + + init { + updateView() + } + + private fun createEditButton(category: Category): Button = + Button("Edit").apply { + icon = Icon(VaadinIcon.EDIT) + addClassName("category__edit") + addThemeVariants(ButtonVariant.LUMO_TERTIARY) + onClick { edit(category) } + } + + private fun edit(category: Category) { + editorDialog.edit(category) + } + + private fun Category.getReviewCount(): String = ReviewService.getTotalCountForReviewsInCategory(id!!).toString() + + private fun updateView() { + val categories: List = CategoryService.findCategories(toolbar.searchText) + if (!toolbar.searchText.isBlank()) { + header.text = "Search for “${toolbar.searchText}”" + } else { + header.text = "Categories" + } + grid.setItems(categories) + } + + private fun saveCategory(category: Category) { + val creating = category.id == null + CategoryService.saveCategory(category) + val op = if (creating) "added" else "saved" + Notification.show("Category successfully ${op}.", 3000, Notification.Position.BOTTOM_START) + updateView() + } + + private fun deleteCategory(category: Category) { + CategoryService.deleteCategory(category) + Notification.show("Category successfully deleted.", 3000, Notification.Position.BOTTOM_START) + updateView() + } +} From f7590732e5706d77c1de5208014b14f217c341bb Mon Sep 17 00:00:00 2001 From: Vitalii Lipovetskii Date: Fri, 10 Jan 2025 18:08:47 +0200 Subject: [PATCH 06/14] + KLitRendererBuilderA.Function + public fun (@VaadinDsl Grid).column( renderer: Renderer, ... ) --- .../ui/categories/CategoriesListLit.kt | 22 +++++++ .../com/github/mvysny/karibudsl/v10/Grid.kt | 26 ++++++++ .../v10/KLitRendererAttributesDsl.kt | 43 ++++++++++++- .../mvysny/karibudsl/v10/KLitRendererDsl.kt | 62 +++++++++++++++++++ .../karibudsl/v10/KLitRendererTagsDsl.kt | 26 +++++++- 5 files changed, 174 insertions(+), 5 deletions(-) diff --git a/example/src/main/kotlin/com/vaadin/starter/beveragebuddy/ui/categories/CategoriesListLit.kt b/example/src/main/kotlin/com/vaadin/starter/beveragebuddy/ui/categories/CategoriesListLit.kt index abee1d16..13501b50 100644 --- a/example/src/main/kotlin/com/vaadin/starter/beveragebuddy/ui/categories/CategoriesListLit.kt +++ b/example/src/main/kotlin/com/vaadin/starter/beveragebuddy/ui/categories/CategoriesListLit.kt @@ -35,6 +35,9 @@ import com.vaadin.starter.beveragebuddy.backend.ReviewService import com.vaadin.starter.beveragebuddy.ui.MainLayout import com.vaadin.starter.beveragebuddy.ui.Toolbar import com.vaadin.starter.beveragebuddy.ui.toolbarView +import kotlinx.css.Align +import kotlinx.css.alignItems +import kotlin.invoke /** * Displays the list of available categories, with a search filter as well as @@ -47,6 +50,7 @@ class CategoriesListLit : KComposite() { private lateinit var header: H3 private lateinit var toolbar: Toolbar private lateinit var grid: Grid + // can't retrieve GridContextMenu from Grid: https://github.com/vaadin/vaadin-grid-flow/issues/523 lateinit var gridContextMenu: GridContextMenu private set @@ -76,6 +80,24 @@ class CategoriesListLit : KComposite() { flexGrow = 0; key = "edit" } + column(buildLitRenderer { + + val onButtonClick = function("onButtonClick") { category -> + edit(category) + } + + templateExpression { + + /** + * Edit + */ + button(cssClass("category__edit"), themeVariant(ButtonVariant.LUMO_TERTIARY), click(onButtonClick)) { + icon(icon(VaadinIcon.EDIT.create())) + +"Edit" + } + } + }) + gridContextMenu = gridContextMenu { item("New", { editorDialog.createNew() }) item("Edit (Alt+E)", { cat -> if (cat != null) edit(cat) }) diff --git a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/Grid.kt b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/Grid.kt index 990ea5c9..7e2438bd 100644 --- a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/Grid.kt +++ b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/Grid.kt @@ -257,6 +257,32 @@ public fun (@VaadinDsl Grid).componentColumn( return column } +/** + * Adds a new column that shows components using [Renderer]. + * + * This is a shorthand for [Grid.addColumn] with a [Renderer]. + * + * *NOTE:* Using [Renderer] (built-in renderers or `LitRenderer`) is more efficient than [ComponentRenderer] + * + * Example of use: + * ```kotlin + * column(buildLitRenderer { ... }) { + * flexGrow = 0; key = "edit" + * } + * ``` + * @param renderer a (built-in renderer or `LitRenderer`) used to create the grid cell structure + * @return the new column + */ +@VaadinDsl +public fun (@VaadinDsl Grid).column( + renderer: Renderer, + block: (@VaadinDsl Grid.Column).() -> Unit = {} +): Grid.Column { + val column = addColumn(renderer) + column.block() + return column +} + /** * Adds a column for given [property]. The column [key] is set to the property name, so that you can look up the column * using `Grid.getColumnBy()`. The column is also by default set to sortable diff --git a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererAttributesDsl.kt b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererAttributesDsl.kt index 16838fb1..31275e16 100644 --- a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererAttributesDsl.kt +++ b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererAttributesDsl.kt @@ -1,6 +1,7 @@ package com.github.mvysny.karibudsl.v10 -import com.vaadin.flow.component.icon.VaadinIcon +import com.vaadin.flow.component.icon.Icon +import com.vaadin.flow.component.shared.ThemeVariant import kotlinx.css.CssBuilder import kotlinx.css.hyphenize @@ -30,6 +31,12 @@ public fun KLitRendererTagsBuilderA.style(block: CssBuilder.( public fun KLitRendererTagsBuilderA.theme(vararg names: KLitRendererTheme) = KLitRendererAttribute("theme", names.joinToString(separator = " ") { it.name }) +public fun KLitRendererTagsBuilderA.themeVariant(vararg names: ThemeVariant) = + KLitRendererAttribute("theme", names.joinToString(separator = " ") { it.variantName }) + +public fun KLitRendererTagsBuilderA.cssClass(vararg names: String) = + KLitRendererAttribute("class", names.joinToString(separator = " ")) + /** * --- Renderers https://vaadin.com/docs/latest/components/grid/renderers * "" @@ -44,6 +51,32 @@ public fun KLitRendererTagsBuilderA.name(value: KLitRendererB public fun KLitRendererTagsBuilderA.src(value: KLitRendererBuilderA.Property) = KLitRendererAttribute("src", value.litItem) +/** + * + * + * Example of use: + * ```kotlin + * val columnIcon = "columnName" { row -> + * if (row.isNew) + * VaadinIcon.PLUS_CIRCLE.createIcon().icon + * else + * VaadinIcon.EDIT.createIcon().icon + * } + * +columnIcon + * ``` + */ +public fun KLitRendererTagsBuilderA.icon(value: KLitRendererBuilderA.Property) = + KLitRendererAttribute("icon", value.litItem) + +/** + * Example of use: + * ```kotlin + * icon(VaadinIcon.EDIT.create()) + * ``` + */ +public fun KLitRendererTagsBuilderA.icon(value: Icon) = + KLitRendererAttribute("icon", value.icon) + public fun KLitRendererTagsBuilderA.img(value: KLitRendererBuilderA.Property) = KLitRendererAttribute("img", value.litItem) @@ -53,5 +86,9 @@ public fun KLitRendererTagsBuilderA.href(value: String) = public fun KLitRendererTagsBuilderA.href(value: KLitRendererBuilderA.Property) = KLitRendererAttribute("href", value.litItem) -public fun KLitRendererTagsBuilderA.icon(value: VaadinIcon) = - KLitRendererAttribute("icon", value.create().icon) + +/* +LitRenderer.of("") + */ +public fun KLitRendererTagsBuilderA.click(value: KLitRendererBuilderA.Function) = + KLitRendererAttribute("@click", value.litItem) diff --git a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererDsl.kt b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererDsl.kt index 8cec7d7d..bd150406 100644 --- a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererDsl.kt +++ b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererDsl.kt @@ -23,8 +23,50 @@ public interface KLitRendererBuilderA { public val litItem: String get() = name.litItem } + /** + * --- withFunction https://vaadin.com/api/platform/com/vaadin/flow/data/renderer/LitRenderer.html#withFunction(java.lang.String,com.vaadin.flow.function.SerializableConsumer) + * @param name This name must be a valid JavaScript function name. It must be alphanumeric and not null, must not be one of the JavaScript reserved words (https://www.w3schools.com/js/js_reserved.asp) + */ + public data class Function( + val name: String, + val handler: (TSource) -> Unit, + ) { + + /** + * NOTE: Rules to validate name of function are created by ChatGPT :) + */ + private companion object { + // JavaScript identifier rules + val identifierRegex = Regex("^[a-zA-Z_\$][a-zA-Z0-9_\$]*$") + + // Reserved keywords in JavaScript + val reservedKeywords = setOf( + "break", "case", "catch", "class", "const", "continue", "debugger", "default", + "delete", "do", "else", "enum", "export", "extends", "false", "finally", + "for", "function", "if", "import", "in", "instanceof", "new", "null", "return", + "super", "switch", "this", "throw", "true", "try", "typeof", "var", "void", + "while", "with", "yield", "let", "await", "static", "implements", "package", + "protected", "interface", "private", "public" + ) + } + + init { + require(identifierRegex.matches(name)) { + "'$name' is not valid JavaScript identifier" + } + + require(name !in reservedKeywords) { + "'$name' is reserved keyword in JavaScript" + } + } + + public val litItem: String get() = "\${$name}" + } + public operator fun String.invoke(provider: (TSource) -> String): Property + public fun function(name: String, handler: (TSource) -> Unit): Function + public fun templateExpression(templateExpression: String) public fun templateExpression(initBlock: KLitRendererTagsBuilderA.() -> Unit) @@ -43,6 +85,7 @@ public class KLitRendererBuilder() : KLitRendererBuilderA { private var templateExpression = "" private val properties = mutableMapOf String>() + private val functions = mutableMapOf Unit>() override fun templateExpression(templateExpression: String) { this.templateExpression = templateExpression.trimIndent() @@ -58,6 +101,9 @@ public class KLitRendererBuilder() : KLitRendererBuilderA { properties.forEach { (name, provider) -> withProperty(name, provider) } + functions.forEach { (name, handler) -> + withFunction(name, handler) + } } @@ -69,6 +115,14 @@ public class KLitRendererBuilder() : KLitRendererBuilderA { properties[it.name] = provider } + override fun function(name: String, handler: (TSource) -> Unit): KLitRendererBuilderA.Function = + KLitRendererBuilderA.Function( + name = name, + handler = handler, + ).also { + functions[it.name] = handler + } + public fun propertyName(property : Property) : String { val provider = properties[property.name] @@ -77,6 +131,14 @@ public class KLitRendererBuilder() : KLitRendererBuilderA { return property.litItem } + public fun functionName(function : KLitRendererBuilderA.Function) : String { + + val handler = functions[function.name] + require(handler != null) { "${function.name} !in ${functions.keys}" } + + return function.litItem + } + } @Suppress("unused") diff --git a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererTagsDsl.kt b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererTagsDsl.kt index 89d0687e..613f74b6 100644 --- a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererTagsDsl.kt +++ b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererTagsDsl.kt @@ -6,6 +6,7 @@ import com.github.mvysny.karibudsl.v10.KLitRendererBuilderA.Property public interface KLitRendererTagsBuilderA { public operator fun Property.unaryPlus() + public operator fun KLitRendererBuilderA.Function.unaryPlus() public operator fun String.unaryPlus() @@ -37,7 +38,12 @@ public interface KLitRendererTagsBuilderA { block: KLitRendererTagsBuilderA.() -> Unit ) - public fun vaadinIcon( + public fun icon( + vararg attributes: KLitRendererAttribute, + block: KLitRendererTagsBuilderA.() -> Unit = {} + ) + + public fun button( vararg attributes: KLitRendererAttribute, block: KLitRendererTagsBuilderA.() -> Unit ) @@ -96,6 +102,15 @@ public class KLitRendererTagsBuilder( ) } + override fun KLitRendererBuilderA.Function.unaryPlus() { + children.add( + KLitRendererTagsBuilder( + litRendererBuilder, + propertyName = (litRendererBuilder as KLitRendererBuilder).functionName(this) + ) + ) + } + override fun String.unaryPlus() { children.add( KLitRendererTagsBuilder( @@ -156,13 +171,20 @@ public class KLitRendererTagsBuilder( addTag("a", attributes.asSequence(), block) } - override fun vaadinIcon( + override fun icon( vararg attributes: KLitRendererAttribute, block: KLitRendererTagsBuilderA.() -> Unit ) { addTag("vaadin-icon", attributes.asSequence(), block) } + override fun button( + vararg attributes: KLitRendererAttribute, + block: KLitRendererTagsBuilderA.() -> Unit + ) { + addTag("vaadin-button", attributes.asSequence(), block) + } + /** * "" * "
${item.name}
" From 52a0b52f4a22be3f0cb6a296d0bacd91dab4f6b4 Mon Sep 17 00:00:00 2001 From: Vitalii Lipovetskii Date: Fri, 10 Jan 2025 18:09:36 +0200 Subject: [PATCH 07/14] + KLitRendererBuilderA.Function + public fun (@VaadinDsl Grid).column( renderer: Renderer, ... ) --- .../starter/beveragebuddy/ui/categories/CategoriesListLit.kt | 3 --- .../src/main/kotlin/com/github/mvysny/karibudsl/v10/Grid.kt | 1 + 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/example/src/main/kotlin/com/vaadin/starter/beveragebuddy/ui/categories/CategoriesListLit.kt b/example/src/main/kotlin/com/vaadin/starter/beveragebuddy/ui/categories/CategoriesListLit.kt index 13501b50..875402eb 100644 --- a/example/src/main/kotlin/com/vaadin/starter/beveragebuddy/ui/categories/CategoriesListLit.kt +++ b/example/src/main/kotlin/com/vaadin/starter/beveragebuddy/ui/categories/CategoriesListLit.kt @@ -35,9 +35,6 @@ import com.vaadin.starter.beveragebuddy.backend.ReviewService import com.vaadin.starter.beveragebuddy.ui.MainLayout import com.vaadin.starter.beveragebuddy.ui.Toolbar import com.vaadin.starter.beveragebuddy.ui.toolbarView -import kotlinx.css.Align -import kotlinx.css.alignItems -import kotlin.invoke /** * Displays the list of available categories, with a search filter as well as diff --git a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/Grid.kt b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/Grid.kt index 7e2438bd..cdd5679b 100644 --- a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/Grid.kt +++ b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/Grid.kt @@ -2,6 +2,7 @@ package com.github.mvysny.karibudsl.v10 import com.github.mvysny.kaributools.addColumnFor import com.github.mvysny.kaributools.addHierarchyColumnFor +import com.github.mvysny.kaributools.getColumnBy import com.vaadin.flow.component.Component import com.vaadin.flow.component.HasComponents import com.vaadin.flow.component.grid.Grid From 568f9e0b3bab06be06c1e94f66f46e71e1782fa9 Mon Sep 17 00:00:00 2001 From: Vitalii Lipovetskii Date: Sat, 11 Jan 2025 16:48:23 +0200 Subject: [PATCH 08/14] - CategoriesListLit.kt column(buildLitRenderer "Edit" -> "Delete" --- .../starter/beveragebuddy/ui/MainLayout.kt | 5 - .../ui/categories/CategoriesList.kt | 25 +++ .../ui/categories/CategoriesListLit.kt | 155 ------------------ .../com/github/mvysny/karibudsl/v10/Grid.kt | 3 +- 4 files changed, 27 insertions(+), 161 deletions(-) delete mode 100644 example/src/main/kotlin/com/vaadin/starter/beveragebuddy/ui/categories/CategoriesListLit.kt diff --git a/example/src/main/kotlin/com/vaadin/starter/beveragebuddy/ui/MainLayout.kt b/example/src/main/kotlin/com/vaadin/starter/beveragebuddy/ui/MainLayout.kt index 239ad51c..50fe86f4 100644 --- a/example/src/main/kotlin/com/vaadin/starter/beveragebuddy/ui/MainLayout.kt +++ b/example/src/main/kotlin/com/vaadin/starter/beveragebuddy/ui/MainLayout.kt @@ -23,7 +23,6 @@ import com.vaadin.flow.component.orderedlayout.VerticalLayout import com.vaadin.flow.router.HighlightConditions import com.vaadin.flow.router.RouterLayout import com.vaadin.starter.beveragebuddy.ui.categories.CategoriesList -import com.vaadin.starter.beveragebuddy.ui.categories.CategoriesListLit import com.vaadin.starter.beveragebuddy.ui.reviews.ReviewsList /** @@ -48,10 +47,6 @@ class MainLayout : KComposite(), RouterLayout { addClassName("main-layout__nav-item") highlightCondition = HighlightConditions.sameLocation() } - routerLink(VaadinIcon.ARCHIVES, "Categories-lit", CategoriesListLit::class) { - addClassName("main-layout__nav-item") - highlightCondition = HighlightConditions.sameLocation() - } } } } diff --git a/example/src/main/kotlin/com/vaadin/starter/beveragebuddy/ui/categories/CategoriesList.kt b/example/src/main/kotlin/com/vaadin/starter/beveragebuddy/ui/categories/CategoriesList.kt index 3b202057..e01d16dd 100644 --- a/example/src/main/kotlin/com/vaadin/starter/beveragebuddy/ui/categories/CategoriesList.kt +++ b/example/src/main/kotlin/com/vaadin/starter/beveragebuddy/ui/categories/CategoriesList.kt @@ -29,6 +29,7 @@ import com.vaadin.flow.component.icon.Icon import com.vaadin.flow.component.icon.VaadinIcon import com.vaadin.flow.component.notification.Notification import com.vaadin.flow.data.renderer.ComponentRenderer +import com.vaadin.flow.data.renderer.Renderer import com.vaadin.flow.router.PageTitle import com.vaadin.flow.router.Route import com.vaadin.starter.beveragebuddy.backend.Category @@ -76,6 +77,30 @@ class CategoriesList : KComposite() { flexGrow = 0; key = "edit" } + /** + * *NOTE:* Using [ComponentRenderer] is not as efficient as the + * built-in renderers or using `LitRenderer`. + * + * *NOTE:* Using [Renderer] (built-in renderers or `LitRenderer`) is more efficient + * than [ComponentRenderer] + */ + column(buildLitRenderer { + + val onButtonClick = function("onButtonClick") { category -> + deleteCategory(category) + } + + templateExpression { + + button(cssClass("category__edit"), themeVariant(ButtonVariant.LUMO_TERTIARY), click(onButtonClick)) { + icon(icon(VaadinIcon.TRASH.create())) + +"Delete" + } + } + }) { + flexGrow = 0; key = "edit-lit" + } + gridContextMenu = gridContextMenu { item("New", { editorDialog.createNew() }) item("Edit (Alt+E)", { cat -> if (cat != null) edit(cat) }) diff --git a/example/src/main/kotlin/com/vaadin/starter/beveragebuddy/ui/categories/CategoriesListLit.kt b/example/src/main/kotlin/com/vaadin/starter/beveragebuddy/ui/categories/CategoriesListLit.kt deleted file mode 100644 index 875402eb..00000000 --- a/example/src/main/kotlin/com/vaadin/starter/beveragebuddy/ui/categories/CategoriesListLit.kt +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright 2000-2017 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.vaadin.starter.beveragebuddy.ui.categories - -import com.github.mvysny.karibudsl.v10.* -import com.github.mvysny.kaributools.ModifierKey.Alt -import com.github.mvysny.kaributools.addShortcut -import com.vaadin.flow.component.Key.KEY_E -import com.vaadin.flow.component.button.Button -import com.vaadin.flow.component.button.ButtonVariant -import com.vaadin.flow.component.grid.Grid -import com.vaadin.flow.component.grid.contextmenu.GridContextMenu -import com.vaadin.flow.component.html.H3 -import com.vaadin.flow.component.icon.Icon -import com.vaadin.flow.component.icon.VaadinIcon -import com.vaadin.flow.component.notification.Notification -import com.vaadin.flow.router.PageTitle -import com.vaadin.flow.router.Route -import com.vaadin.starter.beveragebuddy.backend.Category -import com.vaadin.starter.beveragebuddy.backend.CategoryService -import com.vaadin.starter.beveragebuddy.backend.ReviewService -import com.vaadin.starter.beveragebuddy.ui.MainLayout -import com.vaadin.starter.beveragebuddy.ui.Toolbar -import com.vaadin.starter.beveragebuddy.ui.toolbarView - -/** - * Displays the list of available categories, with a search filter as well as - * buttons to add a new category or edit existing ones. - */ -@Route(value = "categories-lit", layout = MainLayout::class) -@PageTitle("Categories List") -class CategoriesListLit : KComposite() { - - private lateinit var header: H3 - private lateinit var toolbar: Toolbar - private lateinit var grid: Grid - - // can't retrieve GridContextMenu from Grid: https://github.com/vaadin/vaadin-grid-flow/issues/523 - lateinit var gridContextMenu: GridContextMenu - private set - - private val editorDialog = CategoryEditorDialog( - { category -> saveCategory(category) }, - { deleteCategory(it) }) - - private val root = ui { - verticalLayout(false) { - content { align(stretch, top) } - toolbar = toolbarView("New category") { - onSearch = { updateView() } - onCreate = { editorDialog.createNew() } - } - header = h3() - grid = grid { - isExpand = true - - columnFor(Category::name) { - setHeader("Category") - } - column({ it.getReviewCount() }) { - setHeader("Beverages") - } - componentColumn({ cat -> createEditButton(cat) }) { - flexGrow = 0; key = "edit" - } - - column(buildLitRenderer { - - val onButtonClick = function("onButtonClick") { category -> - edit(category) - } - - templateExpression { - - /** - * Edit - */ - button(cssClass("category__edit"), themeVariant(ButtonVariant.LUMO_TERTIARY), click(onButtonClick)) { - icon(icon(VaadinIcon.EDIT.create())) - +"Edit" - } - } - }) - - gridContextMenu = gridContextMenu { - item("New", { editorDialog.createNew() }) - item("Edit (Alt+E)", { cat -> if (cat != null) edit(cat) }) - item("Delete", { cat -> if (cat != null) deleteCategory(cat) }) - } - } - - addShortcut(Alt + KEY_E) { - val category: Category? = grid.asSingleSelect().value - if (category != null) { - edit(category) - } - } - } - } - - init { - updateView() - } - - private fun createEditButton(category: Category): Button = - Button("Edit").apply { - icon = Icon(VaadinIcon.EDIT) - addClassName("category__edit") - addThemeVariants(ButtonVariant.LUMO_TERTIARY) - onClick { edit(category) } - } - - private fun edit(category: Category) { - editorDialog.edit(category) - } - - private fun Category.getReviewCount(): String = ReviewService.getTotalCountForReviewsInCategory(id!!).toString() - - private fun updateView() { - val categories: List = CategoryService.findCategories(toolbar.searchText) - if (!toolbar.searchText.isBlank()) { - header.text = "Search for “${toolbar.searchText}”" - } else { - header.text = "Categories" - } - grid.setItems(categories) - } - - private fun saveCategory(category: Category) { - val creating = category.id == null - CategoryService.saveCategory(category) - val op = if (creating) "added" else "saved" - Notification.show("Category successfully ${op}.", 3000, Notification.Position.BOTTOM_START) - updateView() - } - - private fun deleteCategory(category: Category) { - CategoryService.deleteCategory(category) - Notification.show("Category successfully deleted.", 3000, Notification.Position.BOTTOM_START) - updateView() - } -} diff --git a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/Grid.kt b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/Grid.kt index cdd5679b..ffaa6aae 100644 --- a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/Grid.kt +++ b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/Grid.kt @@ -263,7 +263,8 @@ public fun (@VaadinDsl Grid).componentColumn( * * This is a shorthand for [Grid.addColumn] with a [Renderer]. * - * *NOTE:* Using [Renderer] (built-in renderers or `LitRenderer`) is more efficient than [ComponentRenderer] + * *NOTE:* Using [Renderer] (built-in renderers or `LitRenderer`) is more efficient + * than [ComponentRenderer] * * Example of use: * ```kotlin From 03136cf0f173d7637b03e1896437e787937ab8ea Mon Sep 17 00:00:00 2001 From: Vitalii Lipovetskii Date: Sat, 11 Jan 2025 16:55:58 +0200 Subject: [PATCH 09/14] Fixed warnings --- .../beveragebuddy/ui/categories/CategoriesList.kt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/example/src/main/kotlin/com/vaadin/starter/beveragebuddy/ui/categories/CategoriesList.kt b/example/src/main/kotlin/com/vaadin/starter/beveragebuddy/ui/categories/CategoriesList.kt index e01d16dd..67dd507e 100644 --- a/example/src/main/kotlin/com/vaadin/starter/beveragebuddy/ui/categories/CategoriesList.kt +++ b/example/src/main/kotlin/com/vaadin/starter/beveragebuddy/ui/categories/CategoriesList.kt @@ -16,13 +16,12 @@ package com.vaadin.starter.beveragebuddy.ui.categories import com.github.mvysny.karibudsl.v10.* -import com.github.mvysny.kaributools.ModifierKey.* +import com.github.mvysny.kaributools.ModifierKey.Alt import com.github.mvysny.kaributools.addShortcut -import com.vaadin.flow.component.Key.* +import com.vaadin.flow.component.Key.KEY_E import com.vaadin.flow.component.button.Button import com.vaadin.flow.component.button.ButtonVariant import com.vaadin.flow.component.grid.Grid -import com.vaadin.flow.component.grid.GridVariant import com.vaadin.flow.component.grid.contextmenu.GridContextMenu import com.vaadin.flow.component.html.H3 import com.vaadin.flow.component.icon.Icon @@ -35,7 +34,9 @@ import com.vaadin.flow.router.Route import com.vaadin.starter.beveragebuddy.backend.Category import com.vaadin.starter.beveragebuddy.backend.CategoryService import com.vaadin.starter.beveragebuddy.backend.ReviewService -import com.vaadin.starter.beveragebuddy.ui.* +import com.vaadin.starter.beveragebuddy.ui.MainLayout +import com.vaadin.starter.beveragebuddy.ui.Toolbar +import com.vaadin.starter.beveragebuddy.ui.toolbarView /** * Displays the list of available categories, with a search filter as well as @@ -56,6 +57,7 @@ class CategoriesList : KComposite() { { category -> saveCategory(category) }, { deleteCategory(it) }) + @Suppress("unused") private val root = ui { verticalLayout(false) { content { align(stretch, top) } From a5ed0e50dc4ac0c32cbd348c5dfcdb8f3441013d Mon Sep 17 00:00:00 2001 From: Vitalii Lipovetskii Date: Sat, 11 Jan 2025 17:30:35 +0200 Subject: [PATCH 10/14] Try to fix the CategoriesListTest --- .../vaadin/starter/beveragebuddy/ui/CategoriesListTest.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/example/src/test/kotlin/com/vaadin/starter/beveragebuddy/ui/CategoriesListTest.kt b/example/src/test/kotlin/com/vaadin/starter/beveragebuddy/ui/CategoriesListTest.kt index 0ce7f3fd..4709e720 100644 --- a/example/src/test/kotlin/com/vaadin/starter/beveragebuddy/ui/CategoriesListTest.kt +++ b/example/src/test/kotlin/com/vaadin/starter/beveragebuddy/ui/CategoriesListTest.kt @@ -53,7 +53,7 @@ class CategoriesListTest : AbstractAppTest() { CategoryService.saveCategory(cat) UI.getCurrent().page.reload() val grid = _get>() - grid.expectRow(0, "Beers", "0", "Button[text='Edit', icon='vaadin:edit', @class='category__edit', @theme='tertiary']") + grid.expectRow(0, "Beers", "0", "Button[text='Edit', icon='vaadin:edit', @class='category__edit', @theme='tertiary']", "Delete") grid._clickRenderer(0, "edit") // make sure that the "Edit Category" dialog is opened @@ -66,7 +66,7 @@ class CategoriesListTest : AbstractAppTest() { CategoryService.saveCategory(cat) UI.getCurrent().page.reload() val grid = _get>() - grid.expectRow(0, "Beers", "0", "Button[text='Edit', icon='vaadin:edit', @class='category__edit', @theme='tertiary']") + grid.expectRow(0, "Beers", "0", "Button[text='Edit', icon='vaadin:edit', @class='category__edit', @theme='tertiary']", "Delete") _get().gridContextMenu._clickItemWithCaption("Edit (Alt+E)", cat) // make sure that the "Edit Category" dialog is opened @@ -79,7 +79,7 @@ class CategoriesListTest : AbstractAppTest() { CategoryService.saveCategory(cat) UI.getCurrent().page.reload() val grid = _get>() - grid.expectRow(0, "Beers", "0", "Button[text='Edit', icon='vaadin:edit', @class='category__edit', @theme='tertiary']") + grid.expectRow(0, "Beers", "0", "Button[text='Edit', icon='vaadin:edit', @class='category__edit', @theme='tertiary']", "Delete") _get().gridContextMenu._clickItemWithCaption("Delete", cat) expectList() { CategoryService.findAll() } _get>().expectRows(0) From c153de809225880cd2431852250088da76e44bfa Mon Sep 17 00:00:00 2001 From: Vitalii Lipovetskii Date: Sat, 11 Jan 2025 19:20:47 +0200 Subject: [PATCH 11/14] Fix the CategoriesListTest: grid.expectRow(..., " Delete ") --- .../vaadin/starter/beveragebuddy/ui/CategoriesListTest.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/example/src/test/kotlin/com/vaadin/starter/beveragebuddy/ui/CategoriesListTest.kt b/example/src/test/kotlin/com/vaadin/starter/beveragebuddy/ui/CategoriesListTest.kt index 4709e720..aa7232a6 100644 --- a/example/src/test/kotlin/com/vaadin/starter/beveragebuddy/ui/CategoriesListTest.kt +++ b/example/src/test/kotlin/com/vaadin/starter/beveragebuddy/ui/CategoriesListTest.kt @@ -53,7 +53,7 @@ class CategoriesListTest : AbstractAppTest() { CategoryService.saveCategory(cat) UI.getCurrent().page.reload() val grid = _get>() - grid.expectRow(0, "Beers", "0", "Button[text='Edit', icon='vaadin:edit', @class='category__edit', @theme='tertiary']", "Delete") + grid.expectRow(0, "Beers", "0", "Button[text='Edit', icon='vaadin:edit', @class='category__edit', @theme='tertiary']", " Delete ") grid._clickRenderer(0, "edit") // make sure that the "Edit Category" dialog is opened @@ -66,7 +66,7 @@ class CategoriesListTest : AbstractAppTest() { CategoryService.saveCategory(cat) UI.getCurrent().page.reload() val grid = _get>() - grid.expectRow(0, "Beers", "0", "Button[text='Edit', icon='vaadin:edit', @class='category__edit', @theme='tertiary']", "Delete") + grid.expectRow(0, "Beers", "0", "Button[text='Edit', icon='vaadin:edit', @class='category__edit', @theme='tertiary']", " Delete ") _get().gridContextMenu._clickItemWithCaption("Edit (Alt+E)", cat) // make sure that the "Edit Category" dialog is opened @@ -79,7 +79,7 @@ class CategoriesListTest : AbstractAppTest() { CategoryService.saveCategory(cat) UI.getCurrent().page.reload() val grid = _get>() - grid.expectRow(0, "Beers", "0", "Button[text='Edit', icon='vaadin:edit', @class='category__edit', @theme='tertiary']", "Delete") + grid.expectRow(0, "Beers", "0", "Button[text='Edit', icon='vaadin:edit', @class='category__edit', @theme='tertiary']", " Delete ") _get().gridContextMenu._clickItemWithCaption("Delete", cat) expectList() { CategoryService.findAll() } _get>().expectRows(0) From 571d66c13173caaf157545a0cae0f388f48670ea Mon Sep 17 00:00:00 2001 From: Vitalii Lipovetskii Date: Wed, 15 Jan 2025 18:56:38 +0200 Subject: [PATCH 12/14] + KLitRendererTagsBuilderA.id --- .../github/mvysny/karibudsl/v10/KLitRendererAttributesDsl.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererAttributesDsl.kt b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererAttributesDsl.kt index 31275e16..d03e71d9 100644 --- a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererAttributesDsl.kt +++ b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererAttributesDsl.kt @@ -37,6 +37,9 @@ public fun KLitRendererTagsBuilderA.themeVariant(vararg names public fun KLitRendererTagsBuilderA.cssClass(vararg names: String) = KLitRendererAttribute("class", names.joinToString(separator = " ")) +public fun KLitRendererTagsBuilderA.id(value: String) = + KLitRendererAttribute("id", value) + /** * --- Renderers https://vaadin.com/docs/latest/components/grid/renderers * "" From 5af27d8fd49ff046d9356f1c2d0aad0ba7d76585 Mon Sep 17 00:00:00 2001 From: Vitalii Lipovetskii Date: Wed, 15 Jan 2025 19:23:56 +0200 Subject: [PATCH 13/14] Delegate functions for Property and Function added to generate names from kotlin local variable name automatically. --- .../ui/categories/CategoriesList.kt | 14 +++++++++++- .../mvysny/karibudsl/v10/KLitRendererDsl.kt | 22 +++++++++++++++++-- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/example/src/main/kotlin/com/vaadin/starter/beveragebuddy/ui/categories/CategoriesList.kt b/example/src/main/kotlin/com/vaadin/starter/beveragebuddy/ui/categories/CategoriesList.kt index 67dd507e..755247f1 100644 --- a/example/src/main/kotlin/com/vaadin/starter/beveragebuddy/ui/categories/CategoriesList.kt +++ b/example/src/main/kotlin/com/vaadin/starter/beveragebuddy/ui/categories/CategoriesList.kt @@ -49,6 +49,7 @@ class CategoriesList : KComposite() { private lateinit var header: H3 private lateinit var toolbar: Toolbar private lateinit var grid: Grid + // can't retrieve GridContextMenu from Grid: https://github.com/vaadin/vaadin-grid-flow/issues/523 lateinit var gridContextMenu: GridContextMenu private set @@ -88,17 +89,28 @@ class CategoriesList : KComposite() { */ column(buildLitRenderer { + /* val onButtonClick = function("onButtonClick") { category -> deleteCategory(category) } + */ + // OR + val onButtonClick by function { category -> + deleteCategory(category) + } templateExpression { - button(cssClass("category__edit"), themeVariant(ButtonVariant.LUMO_TERTIARY), click(onButtonClick)) { + button( + cssClass("category__edit"), + themeVariant(ButtonVariant.LUMO_TERTIARY), + click(onButtonClick) + ) { icon(icon(VaadinIcon.TRASH.create())) +"Delete" } } + }) { flexGrow = 0; key = "edit-lit" } diff --git a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererDsl.kt b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererDsl.kt index bd150406..f16ce3b5 100644 --- a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererDsl.kt +++ b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererDsl.kt @@ -2,6 +2,8 @@ package com.github.mvysny.karibudsl.v10 import com.github.mvysny.karibudsl.v10.KLitRendererBuilderA.Property import com.vaadin.flow.data.renderer.LitRenderer +import kotlin.properties.ReadOnlyProperty +import kotlin.reflect.KProperty /** @@ -65,8 +67,12 @@ public interface KLitRendererBuilderA { public operator fun String.invoke(provider: (TSource) -> String): Property + public fun property(provider: (TSource) -> String): ReadOnlyProperty> + public fun function(name: String, handler: (TSource) -> Unit): Function + public fun function(handler: (TSource) -> Unit): ReadOnlyProperty> + public fun templateExpression(templateExpression: String) public fun templateExpression(initBlock: KLitRendererTagsBuilderA.() -> Unit) @@ -115,6 +121,12 @@ public class KLitRendererBuilder() : KLitRendererBuilderA { properties[it.name] = provider } + override fun property(provider: (TSource) -> String): ReadOnlyProperty> = + object : ReadOnlyProperty> { + override fun getValue(thisRef: Any?, property: KProperty<*>): Property = + property.name(provider) + } + override fun function(name: String, handler: (TSource) -> Unit): KLitRendererBuilderA.Function = KLitRendererBuilderA.Function( name = name, @@ -123,7 +135,13 @@ public class KLitRendererBuilder() : KLitRendererBuilderA { functions[it.name] = handler } - public fun propertyName(property : Property) : String { + override fun function(handler: (TSource) -> Unit): ReadOnlyProperty> = + object : ReadOnlyProperty> { + override fun getValue(thisRef: Any?, property: KProperty<*>): KLitRendererBuilderA.Function = + function(property.name, handler) + } + + public fun propertyName(property: Property): String { val provider = properties[property.name] require(provider != null) { "${property.name} !in ${properties.keys}" } @@ -131,7 +149,7 @@ public class KLitRendererBuilder() : KLitRendererBuilderA { return property.litItem } - public fun functionName(function : KLitRendererBuilderA.Function) : String { + public fun functionName(function: KLitRendererBuilderA.Function): String { val handler = functions[function.name] require(handler != null) { "${function.name} !in ${functions.keys}" } From cac1b9ebe25f10229f72275db58fbee997121bea Mon Sep 17 00:00:00 2001 From: Vitalii Lipovetskii Date: Thu, 16 Jan 2025 19:16:28 +0200 Subject: [PATCH 14/14] Updated comments for LitRenderer DSL --- .../mvysny/karibudsl/v10/KCssVarNameA.kt | 15 +++++- .../v10/KLitRendererAttributesDsl.kt | 53 +++++++++++-------- .../mvysny/karibudsl/v10/KLitRendererDsl.kt | 26 ++++----- .../karibudsl/v10/KLitRendererTagsDsl.kt | 37 ++++++++++--- .../mvysny/karibudsl/v10/KLitRendererTheme.kt | 16 ++++-- .../mvysny/karibudsl/v10/KLumoColors.kt | 2 +- .../mvysny/karibudsl/v10/KLumoTypography.kt | 2 +- 7 files changed, 100 insertions(+), 51 deletions(-) diff --git a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KCssVarNameA.kt b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KCssVarNameA.kt index 00f39fe2..bfe37de6 100644 --- a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KCssVarNameA.kt +++ b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KCssVarNameA.kt @@ -1,8 +1,19 @@ package com.github.mvysny.karibudsl.v10 /** - * style="line-height: var(--lumo-line-height-m);" - * style="font-size: var(--lumo-font-size-s); color: var(--lumo-secondary-text-color);" + * [KCssVarNameA] allows you to insert a CSS variable + * [varName] - the name of variable + * [cssValue] - a css representation of the variable + * Example of usage: + * ```kotlin + * verticalLayout(style { lineHeight = +KLumoLineHeight.XS; }) { + * ... + * } + * ``` + * Generated html code: + * ``` + * style="line-height: var(----lumo-font-size-xs);" + * ``` */ public interface KCssVarNameA { public val varName : String diff --git a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererAttributesDsl.kt b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererAttributesDsl.kt index d03e71d9..b7986abe 100644 --- a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererAttributesDsl.kt +++ b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererAttributesDsl.kt @@ -5,6 +5,22 @@ import com.vaadin.flow.component.shared.ThemeVariant import kotlinx.css.CssBuilder import kotlinx.css.hyphenize +/** + * [KLitRendererAttribute] allows you to insert attribute of a html tag + * [name] - the name of attribute + * [value] - the value of attribute + * [toString] - a html representation of the attribute + * Example of usage: + * ```kotlin + * horizontalLayout(theme(spacing)) { + * ... + * } + * ``` + * Generated html code: + * ``` + * theme: "spacing" + * ``` + */ public data class KLitRendererAttribute( val name: String, val value: String @@ -13,9 +29,17 @@ public data class KLitRendererAttribute( } /** - * style="align-items: center;" - * style="line-height: var(--lumo-line-height-m);" - * style="font-size: var(--lumo-font-size-s); color: var(--lumo-secondary-text-color);" + * [buildInlineStyleText] builds text value representation of the [style] attribute. + * Example of usage: + * ``` + * verticalLayout(style { lineHeight = +KLumoLineHeight.XS; }) + * ... + * } + * ``` + * Generated html code: + * ``` + * style="line-height: var(----lumo-font-size-xs);" + * ``` */ private fun CssBuilder.buildInlineStyleText() = declarations.asSequence().joinToString(separator = "; ") { (key, value) -> @@ -40,17 +64,9 @@ public fun KLitRendererTagsBuilderA.cssClass(vararg names: St public fun KLitRendererTagsBuilderA.id(value: String) = KLitRendererAttribute("id", value) -/** - * --- Renderers https://vaadin.com/docs/latest/components/grid/renderers - * "" - */ public fun KLitRendererTagsBuilderA.name(value: KLitRendererBuilderA.Property) = KLitRendererAttribute("name", value.litItem) -/** - * "" - * "
${item.name}
" - */ public fun KLitRendererTagsBuilderA.src(value: KLitRendererBuilderA.Property) = KLitRendererAttribute("src", value.litItem) @@ -59,24 +75,20 @@ public fun KLitRendererTagsBuilderA.src(value: KLitRendererBu * * Example of use: * ```kotlin - * val columnIcon = "columnName" { row -> + * val columnIcon by property { row -> * if (row.isNew) * VaadinIcon.PLUS_CIRCLE.createIcon().icon * else * VaadinIcon.EDIT.createIcon().icon * } - * +columnIcon + * ... + * icon(+columnIcon) + * ... * ``` */ public fun KLitRendererTagsBuilderA.icon(value: KLitRendererBuilderA.Property) = KLitRendererAttribute("icon", value.litItem) -/** - * Example of use: - * ```kotlin - * icon(VaadinIcon.EDIT.create()) - * ``` - */ public fun KLitRendererTagsBuilderA.icon(value: Icon) = KLitRendererAttribute("icon", value.icon) @@ -90,8 +102,5 @@ public fun KLitRendererTagsBuilderA.href(value: KLitRendererB KLitRendererAttribute("href", value.litItem) -/* -LitRenderer.of("") - */ public fun KLitRendererTagsBuilderA.click(value: KLitRendererBuilderA.Function) = KLitRendererAttribute("@click", value.litItem) diff --git a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererDsl.kt b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererDsl.kt index f16ce3b5..ffcf5637 100644 --- a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererDsl.kt +++ b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererDsl.kt @@ -6,14 +6,6 @@ import kotlin.properties.ReadOnlyProperty import kotlin.reflect.KProperty -/** - * PRB: \${item.itemName} -> isn't interpreted by [LitRenderer] - * FAIL: $\{item.itemName} - * --- Templates escaping in Kotlin multiline strings https://stackoverflow.com/questions/32993586/templates-escaping-in-kotlin-multiline-strings - * Solution: ${ "\${item.itemName}" } - */ -public val String.litItem get() = "\${item.$this}" - @Suppress("unused") @VaadinDsl public interface KLitRendererBuilderA { @@ -22,11 +14,11 @@ public interface KLitRendererBuilderA { val name: String, val provider: (TSource) -> String, ) { - public val litItem: String get() = name.litItem + public val litItem: String get() = "\${item.$name}" } /** - * --- withFunction https://vaadin.com/api/platform/com/vaadin/flow/data/renderer/LitRenderer.html#withFunction(java.lang.String,com.vaadin.flow.function.SerializableConsumer) + * [withFunction] (https://vaadin.com/api/platform/com/vaadin/flow/data/renderer/LitRenderer.html#withFunction(java.lang.String,com.vaadin.flow.function.SerializableConsumer)) * @param name This name must be a valid JavaScript function name. It must be alphanumeric and not null, must not be one of the JavaScript reserved words (https://www.w3schools.com/js/js_reserved.asp) */ public data class Function( @@ -80,11 +72,15 @@ public interface KLitRendererBuilderA { } /** - * --- Renderers https://vaadin.com/docs/latest/components/grid/renderers - * --- Display LitRenderer grid cell button as a link in Vaadin 24 https://stackoverflow.com/questions/76984432/display-litrenderer-grid-cell-button-as-a-link-in-vaadin-24 - * --- Vaadin LitRenderer bean exposure to the client https://stackoverflow.com/questions/73101886/vaadin-litrenderer-bean-exposure-to-the-client - * --- How do I implement different row height in a grid - Vaadin Cookbook https://cookbook.vaadin.com/grid-row-height - * --- Dynamically render an image using LitRenderer https://cookbook.vaadin.com/dynamically-render-an-image-using-litrenderer + * [KLitRendererBuilder] is a DSL builder implementation to create [LitRenderer] from [templateExpression], [properties] and [functions] + * See [litRenderer] + * + * Sources of information with examples of LitRenderer usage: + * [Renderers] (https://vaadin.com/docs/latest/components/grid/renderers) + * [Display LitRenderer grid cell button as a link in Vaadin 24] (https://stackoverflow.com/questions/76984432/display-litrenderer-grid-cell-button-as-a-link-in-vaadin-24) + * [Vaadin LitRenderer bean exposure to the client] (https://stackoverflow.com/questions/73101886/vaadin-litrenderer-bean-exposure-to-the-client) + * [How do I implement different row height in a grid - Vaadin Cookbook] (https://cookbook.vaadin.com/grid-row-height) + * [Dynamically render an image using LitRenderer] (https://cookbook.vaadin.com/dynamically-render-an-image-using-litrenderer) */ public class KLitRendererBuilder() : KLitRendererBuilderA { diff --git a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererTagsDsl.kt b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererTagsDsl.kt index 613f74b6..6da256f5 100644 --- a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererTagsDsl.kt +++ b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererTagsDsl.kt @@ -52,6 +52,10 @@ public interface KLitRendererTagsBuilderA { vararg attributes: KLitRendererAttribute, ) + public fun avatar( + vararg attributes: KLitRendererAttribute, + ) + } public class KLitRendererTagsBuilder( @@ -63,7 +67,12 @@ public class KLitRendererTagsBuilder( private val propertyName: String = "", /** - * --- What are Self Closing Tags in HTML? https://www.scaler.com/topics/self-closing-tags-in-html/ + * [What are Self Closing Tags in HTML?] (https://www.scaler.com/topics/self-closing-tags-in-html/) + * A traditional HTML tag such as

,

,
, etc., had an opening tag and a closing tag + * However, due to their fundamental structure, void components in HTML, such as images and links, + * do not technically require closing tags. + * Images and links cannot have content - they are pointers to an element installed on the website. + * See also [img] */ private val selfClosing: Boolean = false, ) : @@ -186,15 +195,25 @@ public class KLitRendererTagsBuilder( } /** - * "" - * "
${item.name}
" - * * [selfClosing] = true - * --- The Image Tag https://www.understandingcode.com/image-tag + * + * [The Image Tag] (https://www.understandingcode.com/image-tag) * The Tag * This tag is different from other tags, in that it has no closing tag. * It is called a self-closing tag, which means that there is just a slash at the end of the opening tag (ex. ) - * --- img tag and / and a lie https://www.codecademy.com/forum_questions/5236c2c9f10c607ef4000bc0 + * [img tag and / and a lie] (https://www.codecademy.com/forum_questions/5236c2c9f10c607ef4000bc0) + * + * Example of usage: + * ```kotlin + * img(src(photo)) + * ... + * } + * ``` + * Generated html code: + * ``` + * "" + * style="line-height: var(----lumo-font-size-xs);" + * ``` */ override fun img( vararg attributes: KLitRendererAttribute, @@ -202,5 +221,11 @@ public class KLitRendererTagsBuilder( addTag("img", attributes.asSequence(), { }, selfClosing = true) } + override fun avatar( + vararg attributes: KLitRendererAttribute, + ) { + addTag("vaadin-avatar", attributes.asSequence(), { }) + } + } diff --git a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererTheme.kt b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererTheme.kt index b8ad0618..bc176a5d 100644 --- a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererTheme.kt +++ b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLitRendererTheme.kt @@ -1,10 +1,18 @@ package com.github.mvysny.karibudsl.v10 /** - * --- Renderers https://vaadin.com/docs/latest/components/grid/renderers - * "" - * --- Vaadin 23 - CSS Remove theme=“padding spacing” https://vaadin.com/forum/t/vaadin-23-css-remove-theme-padding-spacing/167207 - * The CSS and the HTML produced are the same comparing old to new, but for some reason, the theme=“padding spacing” is now causing issues. + * [KLitRendererTheme] type-safe theme names + * + * Example of usage: + * ```kotlin + * horizontalLayout(theme(spacing)) { + * ... + * } + * ``` + * Generated html code: + * ``` + * theme: "spacing" + * ``` */ @Suppress("EnumEntryName") public enum class KLitRendererTheme { diff --git a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLumoColors.kt b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLumoColors.kt index b189e8d3..0d66af6d 100644 --- a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLumoColors.kt +++ b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLumoColors.kt @@ -3,7 +3,7 @@ package com.github.mvysny.karibudsl.v10 import kotlinx.css.Color /** - * --- Lumo Colors https://vaadin.com/docs/latest/styling/lumo/lumo-style-properties/color + * [Lumo Colors] (https://vaadin.com/docs/latest/styling/lumo/lumo-style-properties/color) */ @Suppress("unused", "EnumEntryName") public enum class KLumoPrimaryColor(override val varName: String) : KCssVarNameA { diff --git a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLumoTypography.kt b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLumoTypography.kt index 80e226bc..7d048b98 100644 --- a/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLumoTypography.kt +++ b/karibu-dsl/src/main/kotlin/com/github/mvysny/karibudsl/v10/KLumoTypography.kt @@ -4,7 +4,7 @@ import kotlinx.css.LinearDimension import kotlinx.css.properties.LineHeight /** - * --- Lumo Typography https://vaadin.com/docs/latest/styling/lumo/lumo-style-properties/typography + * [Lumo Typography] (https://vaadin.com/docs/latest/styling/lumo/lumo-style-properties/typography) */ @Suppress("unused", "SpellCheckingInspection") public enum class KLumoFontSize(override val varName: String) : KCssVarNameA {