diff --git a/render-compose-html/build.gradle.kts b/render-compose-html/build.gradle.kts
index ebb4ef3..f632408 100644
--- a/render-compose-html/build.gradle.kts
+++ b/render-compose-html/build.gradle.kts
@@ -16,6 +16,7 @@ kotlin {
implementation(compose.runtime)
implementation(libs.kotlinx.coroutines.core)
api(projects.structures)
+ implementation(projects.renderWebCommon)
}
}
}
diff --git a/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/HtmlComposeRenderer.kt b/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/HtmlComposeRenderer.kt
index 0e9cfa5..9223af6 100644
--- a/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/HtmlComposeRenderer.kt
+++ b/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/HtmlComposeRenderer.kt
@@ -3,9 +3,11 @@ package ink.ui.render.compose.html
import androidx.compose.runtime.Composable
import ink.ui.render.compose.html.renderer.*
import ink.ui.render.compose.html.renderer.CompositeElementRenderer
+import ink.ui.render.web.gridTemplateColumns
import ink.ui.structures.Positioning
import ink.ui.structures.elements.UiElement
import ink.ui.structures.layouts.*
+import ink.ui.structures.render.RenderResult
import org.jetbrains.compose.web.css.*
import org.jetbrains.compose.web.dom.Div
import org.jetbrains.compose.web.dom.Section
@@ -41,7 +43,7 @@ class HtmlComposeRenderer(
attrs = {
classes("fixed-grid")
style {
- gridTemplateColumns((0 until uiLayout.columns).joinToString(" ") { "auto" })
+ gridTemplateColumns(uiLayout.gridTemplateColumns)
}
}
) {
@@ -50,7 +52,6 @@ class HtmlComposeRenderer(
attrs = {
style {
gridColumn("span ${it.span}")
- display(DisplayStyle.Flex)
when (it.horizontalPositioning) {
Positioning.Start -> {
justifyContent(JustifyContent.Start)
@@ -95,8 +96,9 @@ class HtmlComposeRenderer(
@Composable
fun renderElement(element: UiElement) {
- when (uiRenderer.render(element, uiRenderer)) {
- RenderResult.NotRendered -> throw IllegalArgumentException("No renderer registered for ${element::class.simpleName}")
+ when (val result = uiRenderer.render(element, uiRenderer)) {
+ RenderResult.Skipped -> throw IllegalArgumentException("No renderer registered for ${element::class.simpleName}")
+ is RenderResult.Failed -> throw result.exception
RenderResult.Rendered -> {}
}
}
diff --git a/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/ActivityRenderer.kt b/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/ActivityRenderer.kt
index 41a9c93..e89fbf2 100644
--- a/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/ActivityRenderer.kt
+++ b/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/ActivityRenderer.kt
@@ -1,10 +1,12 @@
package ink.ui.render.compose.html.renderer
import androidx.compose.runtime.*
+import ink.ui.render.web.toCssClass
import ink.ui.structures.Sentiment
import ink.ui.structures.elements.ProgressElement
import ink.ui.structures.elements.ThrobberElement
import ink.ui.structures.elements.UiElement
+import ink.ui.structures.render.RenderResult
import kotlinx.coroutines.delay
import org.jetbrains.compose.web.css.*
import org.jetbrains.compose.web.dom.*
@@ -18,7 +20,7 @@ object ActivityRenderer: ElementRenderer {
when (element) {
is ProgressElement -> ProgressBar(element)
is ThrobberElement -> Throbber(element.caption, element.sentiment)
- else -> return RenderResult.NotRendered
+ else -> return RenderResult.Skipped
}
return RenderResult.Rendered
diff --git a/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/ButtonRenderer.kt b/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/ButtonRenderer.kt
index 67964e4..2782074 100644
--- a/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/ButtonRenderer.kt
+++ b/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/ButtonRenderer.kt
@@ -1,37 +1,30 @@
package ink.ui.render.compose.html.renderer
-import androidx.compose.runtime.Composable
+import ink.ui.render.web.svgSrc
+import ink.ui.render.web.toCssClass
import ink.ui.structures.elements.ButtonElement
-import ink.ui.structures.elements.UiElement
import org.jetbrains.compose.web.dom.Button
import org.jetbrains.compose.web.dom.Img
import org.jetbrains.compose.web.dom.Text
-object ButtonRenderer: ElementRenderer {
- @Composable
- override fun render(element: UiElement, parent: ElementRenderer): RenderResult {
- if (element !is ButtonElement) return RenderResult.NotRendered
-
- Button(
- attrs = {
- classes(element.sentiment.toCssClass())
- onClick {
- element.onClick()
- }
- }
- ) {
- val leadingSymbol = element.leadingSymbol
- if (leadingSymbol != null) {
- Img(
- attrs = {
- classes("icon", "svg-fill", element.sentiment.toCssClass())
- },
- src = leadingSymbol.svgSrc,
- )
+val ButtonRenderer = renderer { element ->
+ Button(
+ attrs = {
+ classes(element.sentiment.toCssClass())
+ onClick {
+ element.onClick()
}
- Text(element.text)
}
-
- return RenderResult.Rendered
+ ) {
+ val leadingSymbol = element.leadingSymbol
+ if (leadingSymbol != null) {
+ Img(
+ attrs = {
+ classes("icon", "svg-fill", element.sentiment.toCssClass())
+ },
+ src = leadingSymbol.svgSrc,
+ )
+ }
+ Text(element.text)
}
}
diff --git a/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/CheckBoxRenderer.kt b/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/CheckBoxRenderer.kt
index 8ceb3e2..ad0a697 100644
--- a/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/CheckBoxRenderer.kt
+++ b/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/CheckBoxRenderer.kt
@@ -1,24 +1,15 @@
package ink.ui.render.compose.html.renderer
-import androidx.compose.runtime.Composable
import ink.ui.structures.elements.CheckBoxElement
-import ink.ui.structures.elements.UiElement
import org.jetbrains.compose.web.attributes.InputType
import org.jetbrains.compose.web.dom.Input
-object CheckBoxRenderer: ElementRenderer {
- @Composable
- override fun render(element: UiElement, parent: ElementRenderer): RenderResult {
- if (element !is CheckBoxElement) return RenderResult.NotRendered
-
- Input(
- type = InputType.Checkbox,
- attrs = {
- onClick { element.onClick() }
- checked(element.checked)
- }
- )
-
- return RenderResult.Rendered
- }
+val CheckBoxRenderer = renderer { element ->
+ Input(
+ type = InputType.Checkbox,
+ attrs = {
+ onClick { element.onClick() }
+ checked(element.checked)
+ }
+ )
}
diff --git a/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/CompositeElementRenderer.kt b/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/CompositeElementRenderer.kt
index b42e597..5c17a6a 100644
--- a/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/CompositeElementRenderer.kt
+++ b/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/CompositeElementRenderer.kt
@@ -2,6 +2,8 @@ package ink.ui.render.compose.html.renderer
import androidx.compose.runtime.Composable
import ink.ui.structures.elements.UiElement
+import ink.ui.structures.render.RenderResult
+import ink.ui.structures.render.renderCatching
internal class CompositeElementRenderer(
private val renderers: List = emptyList(),
@@ -9,10 +11,12 @@ internal class CompositeElementRenderer(
@Composable
override fun render(element: UiElement, parent: ElementRenderer): RenderResult {
renderers.forEach { renderer ->
- if (renderer.render(element, this) == RenderResult.Rendered) {
- return RenderResult.Rendered
+ val result = renderCatching { renderer.render(element, this) }
+
+ if (result != RenderResult.Skipped) {
+ return result
}
}
- return RenderResult.NotRendered
+ return RenderResult.Skipped
}
}
diff --git a/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/ElementRenderer.kt b/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/ElementRenderer.kt
index 332d2d6..ad3bc7e 100644
--- a/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/ElementRenderer.kt
+++ b/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/ElementRenderer.kt
@@ -2,6 +2,8 @@ package ink.ui.render.compose.html.renderer
import androidx.compose.runtime.Composable
import ink.ui.structures.elements.UiElement
+import ink.ui.structures.render.RenderResult
+import ink.ui.structures.render.renderCatching
/**
* Renders a UI element in compose.
@@ -13,3 +15,19 @@ interface ElementRenderer {
parent: ElementRenderer
): RenderResult
}
+
+inline fun renderer(
+ crossinline render: @Composable (element: T) -> Unit
+): ElementRenderer = object: ElementRenderer {
+ @Composable
+ override fun render(
+ element: UiElement,
+ parent: ElementRenderer
+ ): RenderResult {
+ if (element !is T) return RenderResult.Skipped
+ return renderCatching {
+ render(element)
+ RenderResult.Rendered
+ }
+ }
+}
diff --git a/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/EmptyRenderer.kt b/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/EmptyRenderer.kt
index 0241113..ed8eb82 100644
--- a/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/EmptyRenderer.kt
+++ b/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/EmptyRenderer.kt
@@ -1,17 +1,8 @@
package ink.ui.render.compose.html.renderer
-import androidx.compose.runtime.Composable
import ink.ui.structures.elements.EmptyElement
-import ink.ui.structures.elements.UiElement
import org.jetbrains.compose.web.dom.Span
-object EmptyRenderer: ElementRenderer {
- @Composable
- override fun render(element: UiElement, parent: ElementRenderer): RenderResult {
- if (element !is EmptyElement) return RenderResult.NotRendered
-
+val EmptyRenderer = renderer { element ->
Span {}
-
- return RenderResult.Rendered
- }
}
diff --git a/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/IconRenderer.kt b/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/IconRenderer.kt
index f6de572..5b37c29 100644
--- a/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/IconRenderer.kt
+++ b/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/IconRenderer.kt
@@ -1,22 +1,15 @@
package ink.ui.render.compose.html.renderer
-import androidx.compose.runtime.Composable
+import ink.ui.render.web.svgSrc
+import ink.ui.render.web.toCssClass
import ink.ui.structures.elements.IconElement
-import ink.ui.structures.elements.UiElement
import org.jetbrains.compose.web.dom.Img
-object IconRenderer: ElementRenderer {
- @Composable
- override fun render(element: UiElement, parent: ElementRenderer): RenderResult {
- if (element !is IconElement) return RenderResult.NotRendered
-
- Img(
- src = element.symbol.svgSrc,
- attrs = {
- classes("icon", "svg-fill", element.sentiment.toCssClass())
- }
- )
-
- return RenderResult.Rendered
- }
+val IconRenderer = renderer { element ->
+ Img(
+ src = element.symbol.svgSrc,
+ attrs = {
+ classes("icon", "svg-fill", element.sentiment.toCssClass())
+ }
+ )
}
diff --git a/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/ListRenderer.kt b/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/ListRenderer.kt
index 90b0c88..968c285 100644
--- a/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/ListRenderer.kt
+++ b/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/ListRenderer.kt
@@ -5,6 +5,7 @@ import ink.ui.structures.GroupingStyle
import ink.ui.structures.Positioning
import ink.ui.structures.elements.ElementList
import ink.ui.structures.elements.UiElement
+import ink.ui.structures.render.RenderResult
import org.jetbrains.compose.web.css.JustifyContent
import org.jetbrains.compose.web.css.justifyContent
import org.jetbrains.compose.web.dom.Div
@@ -12,7 +13,7 @@ import org.jetbrains.compose.web.dom.Div
object ListRenderer: ElementRenderer {
@Composable
override fun render(element: UiElement, parent: ElementRenderer): RenderResult {
- if (element !is ElementList) return RenderResult.NotRendered
+ if (element !is ElementList) return RenderResult.Skipped
Div(
attrs = {
diff --git a/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/MenuRowRenderer.kt b/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/MenuRowRenderer.kt
index d0340a0..31336db 100644
--- a/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/MenuRowRenderer.kt
+++ b/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/MenuRowRenderer.kt
@@ -3,12 +3,13 @@ package ink.ui.render.compose.html.renderer
import androidx.compose.runtime.Composable
import ink.ui.structures.elements.MenuRowElement
import ink.ui.structures.elements.UiElement
+import ink.ui.structures.render.RenderResult
import org.jetbrains.compose.web.dom.*
object MenuRowRenderer: ElementRenderer {
@Composable
override fun render(element: UiElement, parent: ElementRenderer): RenderResult {
- if (element !is MenuRowElement) return RenderResult.NotRendered
+ if (element !is MenuRowElement) return RenderResult.Skipped
val elementOnClick = element.onClick
Div(
attrs = {
diff --git a/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/RenderResult.kt b/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/RenderResult.kt
deleted file mode 100644
index 3ea8e14..0000000
--- a/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/RenderResult.kt
+++ /dev/null
@@ -1,6 +0,0 @@
-package ink.ui.render.compose.html.renderer
-
-enum class RenderResult {
- Rendered,
- NotRendered,
-}
diff --git a/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/Sentiments.kt b/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/Sentiments.kt
deleted file mode 100644
index 46517c0..0000000
--- a/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/Sentiments.kt
+++ /dev/null
@@ -1,14 +0,0 @@
-package ink.ui.render.compose.html.renderer
-
-import ink.ui.structures.Sentiment
-
-fun Sentiment.toCssClass(): String {
- return when (this) {
- Sentiment.Nominal -> "nominal"
- Sentiment.Primary -> "primary"
- Sentiment.Positive -> "positive"
- Sentiment.Negative -> "negative"
- Sentiment.Caution -> "caution"
- Sentiment.Idle -> "idle"
- }
-}
diff --git a/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/SpinnerRenderer.kt b/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/SpinnerRenderer.kt
index 2cd95e1..86233af 100644
--- a/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/SpinnerRenderer.kt
+++ b/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/SpinnerRenderer.kt
@@ -1,54 +1,45 @@
package ink.ui.render.compose.html.renderer
-import androidx.compose.runtime.Composable
import ink.ui.structures.elements.SpinnerElement
-import ink.ui.structures.elements.UiElement
import org.jetbrains.compose.web.attributes.disabled
import org.jetbrains.compose.web.dom.*
-object SpinnerRenderer: ElementRenderer {
- @Composable
- override fun render(element: UiElement, parent: ElementRenderer): RenderResult {
- if (element !is SpinnerElement) return RenderResult.NotRendered
-
- Div(
+val SpinnerRenderer = renderer { element ->
+ Div(
+ attrs = {
+ classes("spinner")
+ }
+ ) {
+ Button(
attrs = {
- classes("spinner")
- }
- ) {
- Button(
- attrs = {
- if (element.hasPreviousValue) {
- onClick { element.onPreviousValue }
- } else {
- disabled()
- }
+ if (element.hasPreviousValue) {
+ onClick { element.onPreviousValue }
+ } else {
+ disabled()
}
- ) {
- Text("<")
}
+ ) {
+ Text("<")
+ }
- Span(
- attrs = {
- classes("spinner-value")
- }
- ) {
- Text(element.value)
+ Span(
+ attrs = {
+ classes("spinner-value")
}
+ ) {
+ Text(element.value)
+ }
- Button(
- attrs = {
- if (element.hasNextValue) {
- onClick { element.onNextValue }
- } else {
- disabled()
- }
+ Button(
+ attrs = {
+ if (element.hasNextValue) {
+ onClick { element.onNextValue }
+ } else {
+ disabled()
}
- ) {
- Text(">")
}
+ ) {
+ Text(">")
}
-
- return RenderResult.Rendered
}
}
diff --git a/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/StatusRenderer.kt b/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/StatusRenderer.kt
index 8c402e3..4c0a897 100644
--- a/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/StatusRenderer.kt
+++ b/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/StatusRenderer.kt
@@ -1,34 +1,27 @@
package ink.ui.render.compose.html.renderer
-import androidx.compose.runtime.Composable
+import ink.ui.render.web.RESOURCE_SVG_PATH
+import ink.ui.render.web.toCssClass
import ink.ui.structures.elements.StatusIndicatorElement
-import ink.ui.structures.elements.UiElement
import org.jetbrains.compose.web.dom.Div
import org.jetbrains.compose.web.dom.Img
import org.jetbrains.compose.web.dom.Span
import org.jetbrains.compose.web.dom.Text
-object StatusRenderer: ElementRenderer {
- @Composable
- override fun render(element: UiElement, parent: ElementRenderer): RenderResult {
- if (element !is StatusIndicatorElement) return RenderResult.NotRendered
-
- Div(
+val StatusRenderer = renderer { element ->
+ Div(
+ attrs = {
+ classes("status-indicator")
+ }
+ ) {
+ Img(
attrs = {
- classes("status-indicator")
- }
- ) {
- Img(
- attrs = {
- classes("status-indicator-blip", "svg-fill", element.sentiment.toCssClass())
- },
- src = "$PATH/blip.svg",
- )
- Span {
- Text(element.text)
- }
+ classes("status-indicator-blip", "svg-fill", element.sentiment.toCssClass())
+ },
+ src = "$RESOURCE_SVG_PATH/blip.svg",
+ )
+ Span {
+ Text(element.text)
}
-
- return RenderResult.Rendered
}
}
diff --git a/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/Symbols.kt b/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/Symbols.kt
deleted file mode 100644
index 7fd082c..0000000
--- a/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/Symbols.kt
+++ /dev/null
@@ -1,33 +0,0 @@
-package ink.ui.render.compose.html.renderer
-
-import ink.ui.structures.Symbol
-
-internal const val PATH = "composeResources/com.inkapplications.ui.render_compose_html.generated.resources/svg"
-
-val Symbol.svgSrc: String get() = when (this) {
- Symbol.Add -> "add.svg"
- Symbol.Alarm -> "alarm.svg"
- Symbol.AlarmOff -> "alarm_off.svg"
- Symbol.ArrowBackward -> "arrow_backward.svg"
- Symbol.ArrowForward -> "arrow_forward.svg"
- Symbol.Bed -> "bed.svg"
- Symbol.Caution -> "caution.svg"
- Symbol.Close -> "close.svg"
- Symbol.Cloud -> "cloud.svg"
- Symbol.Done -> "done.svg"
- Symbol.Edit -> "edit.svg"
- Symbol.Error -> "error.svg"
- Symbol.Group -> "group.svg"
- Symbol.House -> "house.svg"
- Symbol.Lock -> "lock.svg"
- Symbol.LockOpen -> "lock_open.svg"
- Symbol.Moon -> "moon.svg"
- Symbol.Movie -> "movie.svg"
- Symbol.Person -> "person.svg"
- Symbol.Rain -> "rain.svg"
- Symbol.Remove -> "remove.svg"
- Symbol.Sunshine -> "sunshine.svg"
- Symbol.Temperature -> "temperature.svg"
- Symbol.Water -> "water.svg"
- else -> "unknown.svg"
-}.let { "$PATH/$it" }
diff --git a/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/TextRenderer.kt b/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/TextRenderer.kt
index 608e824..8c813dc 100644
--- a/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/TextRenderer.kt
+++ b/render-compose-html/src/jsMain/kotlin/ink/ui/render/compose/html/renderer/TextRenderer.kt
@@ -3,48 +3,40 @@ package ink.ui.render.compose.html.renderer
import androidx.compose.runtime.Composable
import ink.ui.structures.TextStyle
import ink.ui.structures.elements.TextElement
-import ink.ui.structures.elements.UiElement
import org.jetbrains.compose.web.dom.*
-object TextRenderer: ElementRenderer {
- @Composable
- override fun render(element: UiElement, parent: ElementRenderer): RenderResult {
- if (element !is TextElement) return RenderResult.NotRendered
-
- when (element.style) {
- TextStyle.H1 -> H1 {
- Text(element.text)
- }
- TextStyle.H2 -> H2 {
- Text(element.text)
- }
- TextStyle.H3 -> H3 {
- Text(element.text)
- }
- TextStyle.Body -> P(
- attrs = {}
- ) {
- TextWithBreaks(element.text)
- }
- TextStyle.Caption -> P(
- attrs = {
- classes("caption")
- }
- ) {
- TextWithBreaks(element.text)
+val TextRenderer = renderer { element ->
+ when (element.style) {
+ TextStyle.H1 -> H1 {
+ Text(element.text)
+ }
+ TextStyle.H2 -> H2 {
+ Text(element.text)
+ }
+ TextStyle.H3 -> H3 {
+ Text(element.text)
+ }
+ TextStyle.Body -> P(
+ attrs = {}
+ ) {
+ TextWithBreaks(element.text)
+ }
+ TextStyle.Caption -> P(
+ attrs = {
+ classes("caption")
}
+ ) {
+ TextWithBreaks(element.text)
}
-
- return RenderResult.Rendered
}
+}
- @Composable
- private fun TextWithBreaks(text: String) {
- text.split("\n").forEachIndexed { index, line ->
- if (index > 0) {
- Br()
- }
- Text(line)
+@Composable
+private fun TextWithBreaks(text: String) {
+ text.split("\n").forEachIndexed { index, line ->
+ if (index > 0) {
+ Br()
}
+ Text(line)
}
}
diff --git a/render-compose/api/android/render-compose.api b/render-compose/api/android/render-compose.api
index 511dda7..0267baf 100644
--- a/render-compose/api/android/render-compose.api
+++ b/render-compose/api/android/render-compose.api
@@ -11,27 +11,7 @@ public final class ink/ui/render/compose/elements/ButtonKt {
}
public abstract interface class ink/ui/render/compose/renderer/ElementRenderer {
- public abstract fun render (Link/ui/structures/elements/UiElement;Link/ui/render/compose/theme/ComposeRenderTheme;Link/ui/render/compose/renderer/ElementRenderer;Landroidx/compose/runtime/Composer;I)Link/ui/render/compose/renderer/RenderResult;
-}
-
-public final class ink/ui/render/compose/renderer/IconRenderer : ink/ui/render/compose/renderer/ElementRenderer {
- public static final field $stable I
- public static final field INSTANCE Link/ui/render/compose/renderer/IconRenderer;
- public fun render (Link/ui/structures/elements/UiElement;Link/ui/render/compose/theme/ComposeRenderTheme;Link/ui/render/compose/renderer/ElementRenderer;Landroidx/compose/runtime/Composer;I)Link/ui/render/compose/renderer/RenderResult;
-}
-
-public final class ink/ui/render/compose/renderer/RenderResult : java/lang/Enum {
- public static final field NotRendered Link/ui/render/compose/renderer/RenderResult;
- public static final field Rendered Link/ui/render/compose/renderer/RenderResult;
- public static fun getEntries ()Lkotlin/enums/EnumEntries;
- public static fun valueOf (Ljava/lang/String;)Link/ui/render/compose/renderer/RenderResult;
- public static fun values ()[Link/ui/render/compose/renderer/RenderResult;
-}
-
-public final class ink/ui/render/compose/renderer/SpinnerRenderer : ink/ui/render/compose/renderer/ElementRenderer {
- public static final field $stable I
- public static final field INSTANCE Link/ui/render/compose/renderer/SpinnerRenderer;
- public fun render (Link/ui/structures/elements/UiElement;Link/ui/render/compose/theme/ComposeRenderTheme;Link/ui/render/compose/renderer/ElementRenderer;Landroidx/compose/runtime/Composer;I)Link/ui/render/compose/renderer/RenderResult;
+ public abstract fun render (Link/ui/structures/elements/UiElement;Link/ui/render/compose/theme/ComposeRenderTheme;Link/ui/render/compose/renderer/ElementRenderer;Landroidx/compose/runtime/Composer;I)Link/ui/structures/render/RenderResult;
}
public final class ink/ui/render/compose/renderer/SymbolsKt {
diff --git a/render-compose/api/jvm/render-compose.api b/render-compose/api/jvm/render-compose.api
index 511dda7..0267baf 100644
--- a/render-compose/api/jvm/render-compose.api
+++ b/render-compose/api/jvm/render-compose.api
@@ -11,27 +11,7 @@ public final class ink/ui/render/compose/elements/ButtonKt {
}
public abstract interface class ink/ui/render/compose/renderer/ElementRenderer {
- public abstract fun render (Link/ui/structures/elements/UiElement;Link/ui/render/compose/theme/ComposeRenderTheme;Link/ui/render/compose/renderer/ElementRenderer;Landroidx/compose/runtime/Composer;I)Link/ui/render/compose/renderer/RenderResult;
-}
-
-public final class ink/ui/render/compose/renderer/IconRenderer : ink/ui/render/compose/renderer/ElementRenderer {
- public static final field $stable I
- public static final field INSTANCE Link/ui/render/compose/renderer/IconRenderer;
- public fun render (Link/ui/structures/elements/UiElement;Link/ui/render/compose/theme/ComposeRenderTheme;Link/ui/render/compose/renderer/ElementRenderer;Landroidx/compose/runtime/Composer;I)Link/ui/render/compose/renderer/RenderResult;
-}
-
-public final class ink/ui/render/compose/renderer/RenderResult : java/lang/Enum {
- public static final field NotRendered Link/ui/render/compose/renderer/RenderResult;
- public static final field Rendered Link/ui/render/compose/renderer/RenderResult;
- public static fun getEntries ()Lkotlin/enums/EnumEntries;
- public static fun valueOf (Ljava/lang/String;)Link/ui/render/compose/renderer/RenderResult;
- public static fun values ()[Link/ui/render/compose/renderer/RenderResult;
-}
-
-public final class ink/ui/render/compose/renderer/SpinnerRenderer : ink/ui/render/compose/renderer/ElementRenderer {
- public static final field $stable I
- public static final field INSTANCE Link/ui/render/compose/renderer/SpinnerRenderer;
- public fun render (Link/ui/structures/elements/UiElement;Link/ui/render/compose/theme/ComposeRenderTheme;Link/ui/render/compose/renderer/ElementRenderer;Landroidx/compose/runtime/Composer;I)Link/ui/render/compose/renderer/RenderResult;
+ public abstract fun render (Link/ui/structures/elements/UiElement;Link/ui/render/compose/theme/ComposeRenderTheme;Link/ui/render/compose/renderer/ElementRenderer;Landroidx/compose/runtime/Composer;I)Link/ui/structures/render/RenderResult;
}
public final class ink/ui/render/compose/renderer/SymbolsKt {
diff --git a/render-compose/src/commonMain/kotlin/ink/ui/render/compose/ComposeRenderer.kt b/render-compose/src/commonMain/kotlin/ink/ui/render/compose/ComposeRenderer.kt
index 0134963..9dd580e 100644
--- a/render-compose/src/commonMain/kotlin/ink/ui/render/compose/ComposeRenderer.kt
+++ b/render-compose/src/commonMain/kotlin/ink/ui/render/compose/ComposeRenderer.kt
@@ -18,6 +18,7 @@ import ink.ui.render.compose.theme.defaultTheme
import ink.ui.structures.Positioning
import ink.ui.structures.elements.UiElement
import ink.ui.structures.layouts.*
+import ink.ui.structures.render.RenderResult
/**
* Renders UI Layouts and elements using Compose.
@@ -118,8 +119,9 @@ class ComposeRenderer(
@Composable
fun renderElement(element: UiElement) {
- when (uiRenderer.render(element, theme, uiRenderer)) {
- RenderResult.NotRendered -> throw IllegalArgumentException("No renderer registered for ${element::class.simpleName}")
+ when (val result = uiRenderer.render(element, theme, uiRenderer)) {
+ RenderResult.Skipped -> throw IllegalArgumentException("No renderer registered for ${element::class.simpleName}")
+ is RenderResult.Failed -> throw result.exception
RenderResult.Rendered -> {}
}
}
diff --git a/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/ActivityRenderer.kt b/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/ActivityRenderer.kt
index 22e4e93..39a7bc7 100644
--- a/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/ActivityRenderer.kt
+++ b/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/ActivityRenderer.kt
@@ -7,6 +7,7 @@ import ink.ui.render.compose.theme.ComposeRenderTheme
import ink.ui.structures.elements.ProgressElement
import ink.ui.structures.elements.ThrobberElement
import ink.ui.structures.elements.UiElement
+import ink.ui.structures.render.RenderResult
internal object ActivityRenderer: ElementRenderer {
@Composable
@@ -21,7 +22,7 @@ internal object ActivityRenderer: ElementRenderer {
sentiment = element.sentiment,
theme = theme
)
- else -> return RenderResult.NotRendered
+ else -> return RenderResult.Skipped
}
return RenderResult.Rendered
}
diff --git a/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/ButtonRenderer.kt b/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/ButtonRenderer.kt
index 58670f3..0420e80 100644
--- a/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/ButtonRenderer.kt
+++ b/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/ButtonRenderer.kt
@@ -1,26 +1,16 @@
package ink.ui.render.compose.renderer
-import androidx.compose.runtime.Composable
import ink.ui.render.compose.elements.Button
-import ink.ui.render.compose.theme.ComposeRenderTheme
import ink.ui.structures.elements.ButtonElement
-import ink.ui.structures.elements.UiElement
-internal object ButtonRenderer: ElementRenderer {
- @Composable
- override fun render(element: UiElement, theme: ComposeRenderTheme, parent: ElementRenderer): RenderResult {
- when (element) {
- is ButtonElement -> Button(
- text = element.text,
- sentiment = element.sentiment,
- latching = element.latchOnPress,
- leadingSymbol = element.leadingSymbol,
- trailingSymbol = element.trailingSymbol,
- theme = theme,
- onClick = element.onClick,
- )
- else -> return RenderResult.NotRendered
- }
- return RenderResult.Rendered
- }
+internal val ButtonRenderer = renderer { theme, element ->
+ Button(
+ text = element.text,
+ sentiment = element.sentiment,
+ latching = element.latchOnPress,
+ leadingSymbol = element.leadingSymbol,
+ trailingSymbol = element.trailingSymbol,
+ theme = theme,
+ onClick = element.onClick,
+ )
}
diff --git a/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/CheckboxRenderer.kt b/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/CheckboxRenderer.kt
index ac2c0a6..c43eff2 100644
--- a/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/CheckboxRenderer.kt
+++ b/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/CheckboxRenderer.kt
@@ -5,49 +5,39 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.BasicText
-import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import ink.ui.render.compose.theme.ComposeRenderTheme
import ink.ui.structures.elements.CheckBoxElement
-import ink.ui.structures.elements.UiElement
-internal object CheckboxRenderer: ElementRenderer {
- @Composable
- override fun render(element: UiElement, theme: ComposeRenderTheme, parent: ElementRenderer): RenderResult {
- if (element !is CheckBoxElement) return RenderResult.NotRendered
+internal val CheckboxRenderer = renderer { theme, element ->
+ Row(
+ horizontalArrangement = Arrangement.Center,
+ verticalAlignment = Alignment.CenterVertically,
+ modifier = Modifier
+ .clickable(onClick = element.onClick)
+ .padding(theme.spacing.clickSafety / 2)
+ ) {
+ BasicText(
+ text = "[",
+ style = theme.typography.uiGlyph.copy(
+ color = theme.colors.foreground,
+ ),
+ )
- Row(
- horizontalArrangement = Arrangement.Center,
- verticalAlignment = Alignment.CenterVertically,
- modifier = Modifier
- .clickable(onClick = element.onClick)
- .padding(theme.spacing.clickSafety / 2)
- ) {
- BasicText(
- text = "[",
- style = theme.typography.uiGlyph.copy(
- color = theme.colors.foreground,
- ),
- )
+ val centerChar = if (element.checked) "x" else " "
+ val centerColor = theme.colors.foreground
- val centerChar = if (element.checked) "x" else " "
- val centerColor = theme.colors.foreground
-
- BasicText(
- text = centerChar,
- style = theme.typography.uiGlyph.copy(
- color = centerColor,
- ),
- )
- BasicText(
- text = "]",
- style = theme.typography.uiGlyph.copy(
- color = theme.colors.foreground,
- ),
- )
- }
-
- return RenderResult.Rendered
+ BasicText(
+ text = centerChar,
+ style = theme.typography.uiGlyph.copy(
+ color = centerColor,
+ ),
+ )
+ BasicText(
+ text = "]",
+ style = theme.typography.uiGlyph.copy(
+ color = theme.colors.foreground,
+ ),
+ )
}
}
diff --git a/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/CompositeElementRenderer.kt b/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/CompositeElementRenderer.kt
index 96f1ac6..0d36c76 100644
--- a/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/CompositeElementRenderer.kt
+++ b/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/CompositeElementRenderer.kt
@@ -3,6 +3,8 @@ package ink.ui.render.compose.renderer
import androidx.compose.runtime.Composable
import ink.ui.render.compose.theme.ComposeRenderTheme
import ink.ui.structures.elements.UiElement
+import ink.ui.structures.render.RenderResult
+import ink.ui.structures.render.renderCatching
internal class CompositeElementRenderer(
private val renderers: List = emptyList(),
@@ -10,10 +12,12 @@ internal class CompositeElementRenderer(
@Composable
override fun render(element: UiElement, theme: ComposeRenderTheme, parent: ElementRenderer): RenderResult {
renderers.forEach { renderer ->
- if (renderer.render(element, theme, this) == RenderResult.Rendered) {
- return RenderResult.Rendered
+ val result = renderCatching { renderer.render(element, theme, this) }
+
+ if (result != RenderResult.Skipped) {
+ return result
}
}
- return RenderResult.NotRendered
+ return RenderResult.Skipped
}
}
diff --git a/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/ElementRenderer.kt b/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/ElementRenderer.kt
index 275015a..9b90e05 100644
--- a/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/ElementRenderer.kt
+++ b/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/ElementRenderer.kt
@@ -3,6 +3,8 @@ package ink.ui.render.compose.renderer
import androidx.compose.runtime.Composable
import ink.ui.render.compose.theme.ComposeRenderTheme
import ink.ui.structures.elements.UiElement
+import ink.ui.structures.render.RenderResult
+import ink.ui.structures.render.renderCatching
/**
* Renders a UI element in compose.
@@ -15,3 +17,20 @@ interface ElementRenderer {
parent: ElementRenderer
): RenderResult
}
+
+inline fun renderer(
+ crossinline render: @Composable (theme: ComposeRenderTheme, element: T) -> Unit
+): ElementRenderer = object: ElementRenderer {
+ @Composable
+ override fun render(
+ element: UiElement,
+ theme: ComposeRenderTheme,
+ parent: ElementRenderer
+ ): RenderResult {
+ if (element !is T) return RenderResult.Skipped
+ return renderCatching {
+ render(theme, element)
+ RenderResult.Rendered
+ }
+ }
+}
diff --git a/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/EmptyRenderer.kt b/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/EmptyRenderer.kt
index 7684a4e..9c16235 100644
--- a/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/EmptyRenderer.kt
+++ b/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/EmptyRenderer.kt
@@ -1,19 +1,9 @@
package ink.ui.render.compose.renderer
import androidx.compose.foundation.layout.Spacer
-import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
-import ink.ui.render.compose.theme.ComposeRenderTheme
import ink.ui.structures.elements.EmptyElement
-import ink.ui.structures.elements.UiElement
-internal object EmptyRenderer: ElementRenderer {
- @Composable
- override fun render(element: UiElement, theme: ComposeRenderTheme, parent: ElementRenderer): RenderResult {
- when (element) {
- is EmptyElement -> Spacer(Modifier)
- else -> return RenderResult.NotRendered
- }
- return RenderResult.Rendered
- }
+internal val EmptyRenderer = renderer { theme, element ->
+ Spacer(Modifier)
}
diff --git a/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/IconRenderer.kt b/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/IconRenderer.kt
index 8552b0f..9955bb7 100644
--- a/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/IconRenderer.kt
+++ b/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/IconRenderer.kt
@@ -1,24 +1,14 @@
package ink.ui.render.compose.renderer
import androidx.compose.foundation.Image
-import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.ColorFilter
-import ink.ui.render.compose.theme.ComposeRenderTheme
import ink.ui.structures.elements.IconElement
-import ink.ui.structures.elements.UiElement
import org.jetbrains.compose.resources.painterResource
-object IconRenderer: ElementRenderer {
- @Composable
- override fun render(element: UiElement, theme: ComposeRenderTheme, parent: ElementRenderer): RenderResult {
- if (element !is IconElement) return RenderResult.NotRendered
-
- Image(
- painterResource(element.symbol.resource),
- colorFilter = ColorFilter.tint(theme.colors.forSentiment(element.sentiment)),
- contentDescription = null,
- )
-
- return RenderResult.Rendered
- }
+internal val IconRenderer = renderer { theme, element ->
+ Image(
+ painterResource(element.symbol.resource),
+ colorFilter = ColorFilter.tint(theme.colors.forSentiment(element.sentiment)),
+ contentDescription = null,
+ )
}
diff --git a/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/ListRenderer.kt b/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/ListRenderer.kt
index f14a7a3..5039cc4 100644
--- a/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/ListRenderer.kt
+++ b/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/ListRenderer.kt
@@ -11,6 +11,7 @@ import ink.ui.structures.Positioning
import ink.ui.structures.GroupingStyle
import ink.ui.structures.elements.ElementList
import ink.ui.structures.elements.UiElement
+import ink.ui.structures.render.RenderResult
internal object ListRenderer: ElementRenderer {
@Composable
@@ -34,7 +35,7 @@ internal object ListRenderer: ElementRenderer {
}
}
}
- else -> return RenderResult.NotRendered
+ else -> return RenderResult.Skipped
}
return RenderResult.Rendered
}
diff --git a/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/MenuRowRenderer.kt b/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/MenuRowRenderer.kt
index d6d2c47..d94b803 100644
--- a/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/MenuRowRenderer.kt
+++ b/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/MenuRowRenderer.kt
@@ -13,11 +13,12 @@ import androidx.compose.ui.Modifier
import ink.ui.render.compose.theme.ComposeRenderTheme
import ink.ui.structures.elements.MenuRowElement
import ink.ui.structures.elements.UiElement
+import ink.ui.structures.render.RenderResult
internal object MenuRowRenderer: ElementRenderer {
@Composable
override fun render(element: UiElement, theme: ComposeRenderTheme, parent: ElementRenderer): RenderResult {
- if (element !is MenuRowElement) return RenderResult.NotRendered
+ if (element !is MenuRowElement) return RenderResult.Skipped
val onClick = element.onClick
Row(
diff --git a/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/RenderResult.kt b/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/RenderResult.kt
deleted file mode 100644
index 2a24c4c..0000000
--- a/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/RenderResult.kt
+++ /dev/null
@@ -1,6 +0,0 @@
-package ink.ui.render.compose.renderer
-
-enum class RenderResult {
- Rendered,
- NotRendered,
-}
diff --git a/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/SpinnerRenderer.kt b/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/SpinnerRenderer.kt
index fa3137a..3a00412 100644
--- a/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/SpinnerRenderer.kt
+++ b/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/SpinnerRenderer.kt
@@ -3,54 +3,44 @@ package ink.ui.render.compose.renderer
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.text.BasicText
-import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import ink.ui.render.compose.theme.ComposeRenderTheme
import ink.ui.structures.elements.SpinnerElement
-import ink.ui.structures.elements.UiElement
-object SpinnerRenderer: ElementRenderer {
- @Composable
- override fun render(element: UiElement, theme: ComposeRenderTheme, parent: ElementRenderer): RenderResult {
- if (element !is SpinnerElement) return RenderResult.NotRendered
-
- Row(
- horizontalArrangement = Arrangement.SpaceBetween,
- verticalAlignment = Alignment.CenterVertically,
+internal val SpinnerRenderer = renderer { theme, element ->
+ Row(
+ horizontalArrangement = Arrangement.SpaceBetween,
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ Box(
+ modifier = Modifier
+ .let { if (element.hasPreviousValue) it.clickable { element.onPreviousValue() } else it }
+ .padding(theme.spacing.clickSafety / 2)
) {
- Box(
- modifier = Modifier
- .let { if (element.hasPreviousValue) it.clickable { element.onPreviousValue() } else it }
- .padding(theme.spacing.clickSafety / 2)
- ) {
- BasicText(
- text = "-",
- style = theme.typography.uiGlyph.copy(
- color = if (element.hasPreviousValue) theme.colors.foreground else theme.colors.inactive,
- ),
- )
- }
BasicText(
- text = element.value,
- style = theme.typography.body.copy(
- color = theme.colors.primary,
+ text = "-",
+ style = theme.typography.uiGlyph.copy(
+ color = if (element.hasPreviousValue) theme.colors.foreground else theme.colors.inactive,
+ ),
+ )
+ }
+ BasicText(
+ text = element.value,
+ style = theme.typography.body.copy(
+ color = theme.colors.primary,
+ ),
+ )
+ Box(
+ modifier = Modifier
+ .let { if (element.hasNextValue) it.clickable { element.onNextValue() } else it }
+ .padding(theme.spacing.clickSafety / 2)
+ ) {
+ BasicText(
+ text = "+",
+ style = theme.typography.uiGlyph.copy(
+ color = if (element.hasNextValue) theme.colors.foreground else theme.colors.inactive,
),
)
- Box(
- modifier = Modifier
- .let { if (element.hasNextValue) it.clickable { element.onNextValue() } else it }
- .padding(theme.spacing.clickSafety / 2)
- ) {
- BasicText(
- text = "+",
- style = theme.typography.uiGlyph.copy(
- color = if (element.hasNextValue) theme.colors.foreground else theme.colors.inactive,
- ),
- )
- }
}
-
- return RenderResult.Rendered
}
}
diff --git a/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/StatusIndicatorRenderer.kt b/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/StatusIndicatorRenderer.kt
index 6f3dccc..1255ab8 100644
--- a/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/StatusIndicatorRenderer.kt
+++ b/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/StatusIndicatorRenderer.kt
@@ -1,22 +1,12 @@
package ink.ui.render.compose.renderer
-import androidx.compose.runtime.Composable
import ink.ui.render.compose.elements.StatusIndicator
-import ink.ui.render.compose.theme.ComposeRenderTheme
import ink.ui.structures.elements.StatusIndicatorElement
-import ink.ui.structures.elements.UiElement
-internal object StatusIndicatorRenderer: ElementRenderer {
- @Composable
- override fun render(element: UiElement, theme: ComposeRenderTheme, parent: ElementRenderer): RenderResult {
- when (element) {
- is StatusIndicatorElement -> StatusIndicator(
- text = element.text,
- sentiment = element.sentiment,
- theme = theme,
- )
- else -> return RenderResult.NotRendered
- }
- return RenderResult.Rendered
- }
+internal val StatusIndicatorRenderer = renderer { theme, element ->
+ StatusIndicator(
+ text = element.text,
+ sentiment = element.sentiment,
+ theme = theme,
+ )
}
diff --git a/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/TextRenderer.kt b/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/TextRenderer.kt
index 477eb1d..6119357 100644
--- a/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/TextRenderer.kt
+++ b/render-compose/src/commonMain/kotlin/ink/ui/render/compose/renderer/TextRenderer.kt
@@ -1,28 +1,18 @@
package ink.ui.render.compose.renderer
import androidx.compose.foundation.text.BasicText
-import androidx.compose.runtime.Composable
-import ink.ui.render.compose.theme.ComposeRenderTheme
import ink.ui.structures.TextStyle
import ink.ui.structures.elements.TextElement
-import ink.ui.structures.elements.UiElement
-internal object TextRenderer: ElementRenderer {
- @Composable
- override fun render(element: UiElement, theme: ComposeRenderTheme, parent: ElementRenderer): RenderResult {
- when (element) {
- is TextElement -> BasicText(
- text = element.text,
- style = when (element.style) {
- TextStyle.H1 -> theme.typography.h1
- TextStyle.H2 -> theme.typography.h2
- TextStyle.H3 -> theme.typography.h3
- TextStyle.Body -> theme.typography.body
- TextStyle.Caption -> theme.typography.caption
- }.copy(color = theme.colors.foreground),
- )
- else -> return RenderResult.NotRendered
- }
- return RenderResult.Rendered
- }
+internal val TextRenderer = renderer { theme, element ->
+ BasicText(
+ text = element.text,
+ style = when (element.style) {
+ TextStyle.H1 -> theme.typography.h1
+ TextStyle.H2 -> theme.typography.h2
+ TextStyle.H3 -> theme.typography.h3
+ TextStyle.Body -> theme.typography.body
+ TextStyle.Caption -> theme.typography.caption
+ }.copy(color = theme.colors.foreground),
+ )
}
diff --git a/render-static-html/api/render-static-html.api b/render-static-html/api/render-static-html.api
new file mode 100644
index 0000000..436ce77
--- /dev/null
+++ b/render-static-html/api/render-static-html.api
@@ -0,0 +1,60 @@
+public final class ink/ui/render/statichtml/HtmlRenderer {
+ public fun ()V
+ public final fun renderDocument (Ljava/lang/String;Ljava/util/List;Ljava/util/List;Ljava/util/List;ZZ)Ljava/lang/String;
+ public static synthetic fun renderDocument$default (Link/ui/render/statichtml/HtmlRenderer;Ljava/lang/String;Ljava/util/List;Ljava/util/List;Ljava/util/List;ZZILjava/lang/Object;)Ljava/lang/String;
+ public final fun renderElement (Link/ui/structures/elements/UiElement;)Lkotlin/jvm/functions/Function1;
+ public final fun renderLayout (Link/ui/structures/layouts/UiLayout;)Lkotlin/jvm/functions/Function1;
+}
+
+public final class ink/ui/render/statichtml/InkUiConfig : kotlin/script/experimental/api/ScriptCompilationConfiguration {
+ public static final field INSTANCE Link/ui/render/statichtml/InkUiConfig;
+}
+
+public abstract class ink/ui/render/statichtml/InkUiScript {
+ public static final field Companion Link/ui/render/statichtml/InkUiScript$Companion;
+ public fun ()V
+ public final fun addBody (Link/ui/structures/layouts/UiLayout;)V
+ public final fun addBody (Lkotlin/jvm/functions/Function1;)V
+ public final fun addPageHeader (Link/ui/structures/elements/UiElement;)V
+ public final fun addPageHeader (Lkotlin/jvm/functions/Function1;)V
+ public final fun addStyle (Ljava/lang/String;)V
+ public final fun getContentBreak ()Z
+ public final fun getResourceBaseUrl ()Ljava/lang/String;
+ public final fun getSectioned ()Z
+ public final fun getTitle ()Ljava/lang/String;
+ public final fun setContentBreak (Z)V
+ public final fun setResourceBaseUrl (Ljava/lang/String;)V
+ public final fun setSectioned (Z)V
+ public final fun setTitle (Ljava/lang/String;)V
+}
+
+public final class ink/ui/render/statichtml/InkUiScript$Companion {
+}
+
+public final class ink/ui/render/statichtml/MainKt {
+ public static final fun main ([Ljava/lang/String;)V
+}
+
+public abstract interface class ink/ui/render/statichtml/renderer/ElementRenderer {
+ public abstract fun render (Lkotlinx/html/TagConsumer;Link/ui/structures/elements/UiElement;Link/ui/render/statichtml/renderer/ElementRenderer;)Link/ui/structures/render/RenderResult;
+}
+
+public final class ink/ui/render/statichtml/renderer/ElementRendererKt {
+ public static final fun renderWith (Link/ui/structures/elements/UiElement;Lkotlinx/html/TagConsumer;Link/ui/render/statichtml/renderer/ElementRenderer;Link/ui/render/statichtml/renderer/ElementRenderer;)Link/ui/structures/render/RenderResult;
+ public static synthetic fun renderWith$default (Link/ui/structures/elements/UiElement;Lkotlinx/html/TagConsumer;Link/ui/render/statichtml/renderer/ElementRenderer;Link/ui/render/statichtml/renderer/ElementRenderer;ILjava/lang/Object;)Link/ui/structures/render/RenderResult;
+}
+
+public final class ink/ui/render/statichtml/renderer/FormattedTextRendererKt {
+ public static final fun getFormattedTextRenderer ()Link/ui/render/statichtml/renderer/ElementRenderer;
+}
+
+public final class ink/ui/render/statichtml/renderer/ListRenderer : ink/ui/render/statichtml/renderer/ElementRenderer {
+ public static final field INSTANCE Link/ui/render/statichtml/renderer/ListRenderer;
+ public fun render (Lkotlinx/html/TagConsumer;Link/ui/structures/elements/UiElement;Link/ui/render/statichtml/renderer/ElementRenderer;)Link/ui/structures/render/RenderResult;
+}
+
+public final class ink/ui/render/statichtml/renderer/StatusRenderer : ink/ui/render/statichtml/renderer/ElementRenderer {
+ public fun (Ljava/lang/String;)V
+ public fun render (Lkotlinx/html/TagConsumer;Link/ui/structures/elements/UiElement;Link/ui/render/statichtml/renderer/ElementRenderer;)Link/ui/structures/render/RenderResult;
+}
+
diff --git a/render-static-html/build.gradle.kts b/render-static-html/build.gradle.kts
index 88d509c..969abdc 100644
--- a/render-static-html/build.gradle.kts
+++ b/render-static-html/build.gradle.kts
@@ -1,6 +1,7 @@
plugins {
application
kotlin("jvm")
+ id("ink.publishing")
}
application {
@@ -15,4 +16,5 @@ dependencies {
implementation(libs.kotlin.scripting.jvm.host)
implementation(libs.kotlinx.html)
api(projects.structures)
+ implementation(projects.renderWebCommon)
}
diff --git a/render-static-html/src/main/java/ink/ui/render/statichtml/HtmlRenderer.kt b/render-static-html/src/main/java/ink/ui/render/statichtml/HtmlRenderer.kt
index bf53b83..beb5485 100644
--- a/render-static-html/src/main/java/ink/ui/render/statichtml/HtmlRenderer.kt
+++ b/render-static-html/src/main/java/ink/ui/render/statichtml/HtmlRenderer.kt
@@ -3,6 +3,9 @@ package ink.ui.render.statichtml
import ink.ui.render.statichtml.renderer.*
import ink.ui.render.statichtml.renderer.CompositeElementRenderer
import ink.ui.render.statichtml.renderer.TextRenderer
+import ink.ui.render.web.gridTemplateColumns
+import ink.ui.structures.Positioning
+import ink.ui.structures.elements.ElementList
import ink.ui.structures.elements.UiElement
import ink.ui.structures.layouts.*
import kotlinx.html.*
@@ -13,6 +16,7 @@ class HtmlRenderer {
private val builtInRenderers = listOf(
ListRenderer,
TextRenderer,
+ FormattedTextRenderer,
StatusRenderer(null)
)
private val renderer = CompositeElementRenderer(builtInRenderers)
@@ -25,17 +29,51 @@ class HtmlRenderer {
)
}
- fun renderLayout(uiLayout: UiLayout): TagConsumer<*>.() -> Unit = {
+ fun renderLayout(uiLayout: UiLayout): TagConsumer<*>.() -> Unit = consumer@ {
when (uiLayout) {
- is CenteredElementLayout -> TODO()
- is FixedGridLayout -> TODO()
- is PageLayout -> section {
- with(renderer) {
- render(uiLayout.body, renderer)
- }
+ is CenteredElementLayout -> section("element-center") {
+ renderWith(
+ element = uiLayout.body,
+ consumer = consumer,
+ renderer = renderer,
+ )
}
+ is FixedGridLayout -> section("fixed-grid") {
+ attributes["style"] = "grid-template-columns: ${uiLayout.gridTemplateColumns};"
- is ScrollingListLayout -> TODO()
+ uiLayout.items.forEach { item ->
+ div {
+ val horizontalPosition = when (item.horizontalPositioning) {
+ Positioning.Start -> "start"
+ Positioning.Center -> "center"
+ }
+ val verticalPosition = when (item.verticalPositioning) {
+ Positioning.Start -> "start"
+ Positioning.Center -> "center"
+ }
+ attributes["style"] = "grid-column: span ${item.span}; align-items: $verticalPosition; justify-content: $horizontalPosition;"
+ renderWith(
+ element = item.body,
+ consumer = consumer,
+ renderer = renderer,
+ )
+ }
+ }
+ }
+ is PageLayout -> section {
+ renderWith(
+ element = uiLayout.body,
+ consumer = consumer,
+ renderer = renderer,
+ )
+ }
+ is ScrollingListLayout -> section {
+ renderWith(
+ element = ElementList(uiLayout.items),
+ consumer = consumer,
+ renderer = renderer,
+ )
+ }
}
}
diff --git a/render-static-html/src/main/java/ink/ui/render/statichtml/renderer/CompositeElementRenderer.kt b/render-static-html/src/main/java/ink/ui/render/statichtml/renderer/CompositeElementRenderer.kt
index f5ebce2..9e43e14 100644
--- a/render-static-html/src/main/java/ink/ui/render/statichtml/renderer/CompositeElementRenderer.kt
+++ b/render-static-html/src/main/java/ink/ui/render/statichtml/renderer/CompositeElementRenderer.kt
@@ -1,6 +1,8 @@
package ink.ui.render.statichtml.renderer
import ink.ui.structures.elements.UiElement
+import ink.ui.structures.render.RenderResult
+import ink.ui.structures.render.renderCatching
import kotlinx.html.TagConsumer
internal class CompositeElementRenderer(
@@ -8,16 +10,18 @@ internal class CompositeElementRenderer(
): ElementRenderer {
override fun TagConsumer<*>.render(element: UiElement, parent: ElementRenderer): RenderResult {
renderers.forEach { renderer ->
- val result = renderWith(
- element = element,
- consumer = this@render,
- renderer = renderer,
- parent = this@CompositeElementRenderer,
- )
- if (result == RenderResult.Rendered) {
- return RenderResult.Rendered
+ val result = renderCatching {
+ renderWith(
+ element = element,
+ consumer = this@render,
+ renderer = renderer,
+ parent = this@CompositeElementRenderer,
+ )
+ }
+ if (result != RenderResult.Skipped) {
+ return result
}
}
- return RenderResult.NotRendered
+ return RenderResult.Skipped
}
}
diff --git a/render-static-html/src/main/java/ink/ui/render/statichtml/renderer/ElementRenderer.kt b/render-static-html/src/main/java/ink/ui/render/statichtml/renderer/ElementRenderer.kt
index 5dfbf48..93a66fd 100644
--- a/render-static-html/src/main/java/ink/ui/render/statichtml/renderer/ElementRenderer.kt
+++ b/render-static-html/src/main/java/ink/ui/render/statichtml/renderer/ElementRenderer.kt
@@ -1,19 +1,20 @@
package ink.ui.render.statichtml.renderer
import ink.ui.structures.elements.UiElement
+import ink.ui.structures.render.RenderResult
import kotlinx.html.TagConsumer
interface ElementRenderer {
fun TagConsumer<*>.render(element: UiElement, parent: ElementRenderer): RenderResult
}
-inline fun renderer(crossinline render: TagConsumer<*>.(T) -> Unit) = object: ElementRenderer{
+inline fun renderer(crossinline render: TagConsumer<*>.(T) -> Unit) = object: ElementRenderer {
override fun TagConsumer<*>.render(element: UiElement, parent: ElementRenderer): RenderResult {
if (element is T) {
render(element)
return RenderResult.Rendered
}
- return RenderResult.NotRendered
+ return RenderResult.Skipped
}
}
diff --git a/render-static-html/src/main/java/ink/ui/render/statichtml/renderer/FormattedTextRenderer.kt b/render-static-html/src/main/java/ink/ui/render/statichtml/renderer/FormattedTextRenderer.kt
new file mode 100644
index 0000000..4d68d72
--- /dev/null
+++ b/render-static-html/src/main/java/ink/ui/render/statichtml/renderer/FormattedTextRenderer.kt
@@ -0,0 +1,33 @@
+package ink.ui.render.statichtml.renderer
+
+import ink.ui.structures.elements.FormattedText
+import kotlinx.html.TagConsumer
+import kotlinx.html.*
+
+val FormattedTextRenderer = renderer { element ->
+ p {
+ render(consumer, element.spans)
+ }
+}
+
+private fun Tag.render(
+ consumer: TagConsumer<*>,
+ spans: List,
+) {
+ spans.forEachIndexed { index, span ->
+ when (span) {
+ is FormattedText.Span.Text -> +span.text
+ is FormattedText.Span.Emphasis -> consumer.em {
+ render(consumer, span.inner)
+ }
+ is FormattedText.Span.Link -> consumer.a(
+ href = span.url,
+ ) {
+ render(consumer, span.inner)
+ }
+ is FormattedText.Span.Strong -> consumer.strong {
+ render(consumer, span.inner)
+ }
+ }
+ }
+}
diff --git a/render-static-html/src/main/java/ink/ui/render/statichtml/renderer/ListRenderer.kt b/render-static-html/src/main/java/ink/ui/render/statichtml/renderer/ListRenderer.kt
index 7cf846d..0060969 100644
--- a/render-static-html/src/main/java/ink/ui/render/statichtml/renderer/ListRenderer.kt
+++ b/render-static-html/src/main/java/ink/ui/render/statichtml/renderer/ListRenderer.kt
@@ -4,11 +4,12 @@ import ink.ui.structures.GroupingStyle
import ink.ui.structures.Positioning
import ink.ui.structures.elements.ElementList
import ink.ui.structures.elements.UiElement
+import ink.ui.structures.render.RenderResult
import kotlinx.html.*
object ListRenderer: ElementRenderer {
override fun TagConsumer<*>.render(element: UiElement, parent: ElementRenderer): RenderResult {
- if (element !is ElementList) return RenderResult.NotRendered
+ if (element !is ElementList) return RenderResult.Skipped
div(
classes = when (element.groupingStyle) {
diff --git a/render-static-html/src/main/java/ink/ui/render/statichtml/renderer/RenderResult.kt b/render-static-html/src/main/java/ink/ui/render/statichtml/renderer/RenderResult.kt
deleted file mode 100644
index 2a28460..0000000
--- a/render-static-html/src/main/java/ink/ui/render/statichtml/renderer/RenderResult.kt
+++ /dev/null
@@ -1,6 +0,0 @@
-package ink.ui.render.statichtml.renderer
-
-enum class RenderResult {
- Rendered,
- NotRendered,
-}
diff --git a/render-static-html/src/main/java/ink/ui/render/statichtml/renderer/StatusRenderer.kt b/render-static-html/src/main/java/ink/ui/render/statichtml/renderer/StatusRenderer.kt
index d14117d..7db7c18 100644
--- a/render-static-html/src/main/java/ink/ui/render/statichtml/renderer/StatusRenderer.kt
+++ b/render-static-html/src/main/java/ink/ui/render/statichtml/renderer/StatusRenderer.kt
@@ -1,14 +1,16 @@
package ink.ui.render.statichtml.renderer
+import ink.ui.render.web.toCssClass
import ink.ui.structures.elements.StatusIndicatorElement
import ink.ui.structures.elements.UiElement
+import ink.ui.structures.render.RenderResult
import kotlinx.html.*
class StatusRenderer(
private val iconPath: String?
): ElementRenderer {
override fun TagConsumer<*>.render(element: UiElement, parent: ElementRenderer): RenderResult {
- if (element !is StatusIndicatorElement) return RenderResult.NotRendered
+ if (element !is StatusIndicatorElement) return RenderResult.Skipped
div(classes = "status-indicator") {
if(iconPath != null) {
eagerImg(
diff --git a/render-web-common/api/render-web-common.api b/render-web-common/api/render-web-common.api
new file mode 100644
index 0000000..1204a95
--- /dev/null
+++ b/render-web-common/api/render-web-common.api
@@ -0,0 +1,13 @@
+public final class ink/ui/render/web/FixedGridLayoutsKt {
+ public static final fun getGridTemplateColumns (Link/ui/structures/layouts/FixedGridLayout;)Ljava/lang/String;
+}
+
+public final class ink/ui/render/web/SentimentsKt {
+ public static final fun toCssClass (Link/ui/structures/Sentiment;)Ljava/lang/String;
+}
+
+public final class ink/ui/render/web/SymbolsKt {
+ public static final field RESOURCE_SVG_PATH Ljava/lang/String;
+ public static final fun getSvgSrc-TN8vZ0Q (Ljava/lang/String;)Ljava/lang/String;
+}
+
diff --git a/render-web-common/build.gradle.kts b/render-web-common/build.gradle.kts
new file mode 100644
index 0000000..4f2adb4
--- /dev/null
+++ b/render-web-common/build.gradle.kts
@@ -0,0 +1,21 @@
+plugins {
+ kotlin("multiplatform")
+ id("org.jetbrains.compose")
+ id("org.jetbrains.kotlin.plugin.compose")
+ id("ink.publishing")
+}
+kotlin {
+ js {
+ browser()
+ binaries.executable()
+ }
+ jvm()
+
+ sourceSets {
+ commonMain.dependencies {
+ api(libs.kotlinx.coroutines.core)
+ implementation(compose.runtime)
+ api(projects.structures)
+ }
+ }
+}
diff --git a/render-compose-html/src/commonMain/composeResources/css/main-2.0.css b/render-web-common/src/commonMain/composeResources/css/main-2.0.css
similarity index 99%
rename from render-compose-html/src/commonMain/composeResources/css/main-2.0.css
rename to render-web-common/src/commonMain/composeResources/css/main-2.0.css
index fbf07cc..da54da7 100644
--- a/render-compose-html/src/commonMain/composeResources/css/main-2.0.css
+++ b/render-web-common/src/commonMain/composeResources/css/main-2.0.css
@@ -241,6 +241,10 @@ section nav a:not(.button):after
display: grid;
gap: .25rem;
}
+.fixed-grid > *
+{
+ display: flex;
+}
.item-list,
.unified-list,
diff --git a/render-compose-html/src/commonMain/composeResources/css/reset.css b/render-web-common/src/commonMain/composeResources/css/reset.css
similarity index 100%
rename from render-compose-html/src/commonMain/composeResources/css/reset.css
rename to render-web-common/src/commonMain/composeResources/css/reset.css
diff --git a/render-compose-html/src/commonMain/composeResources/svg/add.svg b/render-web-common/src/commonMain/composeResources/svg/add.svg
similarity index 100%
rename from render-compose-html/src/commonMain/composeResources/svg/add.svg
rename to render-web-common/src/commonMain/composeResources/svg/add.svg
diff --git a/render-compose-html/src/commonMain/composeResources/svg/alarm.svg b/render-web-common/src/commonMain/composeResources/svg/alarm.svg
similarity index 100%
rename from render-compose-html/src/commonMain/composeResources/svg/alarm.svg
rename to render-web-common/src/commonMain/composeResources/svg/alarm.svg
diff --git a/render-compose-html/src/commonMain/composeResources/svg/alarm_off.svg b/render-web-common/src/commonMain/composeResources/svg/alarm_off.svg
similarity index 100%
rename from render-compose-html/src/commonMain/composeResources/svg/alarm_off.svg
rename to render-web-common/src/commonMain/composeResources/svg/alarm_off.svg
diff --git a/render-compose-html/src/commonMain/composeResources/svg/arrow_back.svg b/render-web-common/src/commonMain/composeResources/svg/arrow_back.svg
similarity index 100%
rename from render-compose-html/src/commonMain/composeResources/svg/arrow_back.svg
rename to render-web-common/src/commonMain/composeResources/svg/arrow_back.svg
diff --git a/render-compose-html/src/commonMain/composeResources/svg/arrow_forward.svg b/render-web-common/src/commonMain/composeResources/svg/arrow_forward.svg
similarity index 100%
rename from render-compose-html/src/commonMain/composeResources/svg/arrow_forward.svg
rename to render-web-common/src/commonMain/composeResources/svg/arrow_forward.svg
diff --git a/render-compose-html/src/commonMain/composeResources/svg/bed.svg b/render-web-common/src/commonMain/composeResources/svg/bed.svg
similarity index 100%
rename from render-compose-html/src/commonMain/composeResources/svg/bed.svg
rename to render-web-common/src/commonMain/composeResources/svg/bed.svg
diff --git a/render-compose-html/src/commonMain/composeResources/svg/blip.svg b/render-web-common/src/commonMain/composeResources/svg/blip.svg
similarity index 100%
rename from render-compose-html/src/commonMain/composeResources/svg/blip.svg
rename to render-web-common/src/commonMain/composeResources/svg/blip.svg
diff --git a/render-compose-html/src/commonMain/composeResources/svg/caution.svg b/render-web-common/src/commonMain/composeResources/svg/caution.svg
similarity index 100%
rename from render-compose-html/src/commonMain/composeResources/svg/caution.svg
rename to render-web-common/src/commonMain/composeResources/svg/caution.svg
diff --git a/render-compose-html/src/commonMain/composeResources/svg/close.svg b/render-web-common/src/commonMain/composeResources/svg/close.svg
similarity index 100%
rename from render-compose-html/src/commonMain/composeResources/svg/close.svg
rename to render-web-common/src/commonMain/composeResources/svg/close.svg
diff --git a/render-compose-html/src/commonMain/composeResources/svg/cloud.svg b/render-web-common/src/commonMain/composeResources/svg/cloud.svg
similarity index 100%
rename from render-compose-html/src/commonMain/composeResources/svg/cloud.svg
rename to render-web-common/src/commonMain/composeResources/svg/cloud.svg
diff --git a/render-compose-html/src/commonMain/composeResources/svg/done.svg b/render-web-common/src/commonMain/composeResources/svg/done.svg
similarity index 100%
rename from render-compose-html/src/commonMain/composeResources/svg/done.svg
rename to render-web-common/src/commonMain/composeResources/svg/done.svg
diff --git a/render-compose-html/src/commonMain/composeResources/svg/edit.svg b/render-web-common/src/commonMain/composeResources/svg/edit.svg
similarity index 100%
rename from render-compose-html/src/commonMain/composeResources/svg/edit.svg
rename to render-web-common/src/commonMain/composeResources/svg/edit.svg
diff --git a/render-compose-html/src/commonMain/composeResources/svg/error.svg b/render-web-common/src/commonMain/composeResources/svg/error.svg
similarity index 100%
rename from render-compose-html/src/commonMain/composeResources/svg/error.svg
rename to render-web-common/src/commonMain/composeResources/svg/error.svg
diff --git a/render-compose-html/src/commonMain/composeResources/svg/group.svg b/render-web-common/src/commonMain/composeResources/svg/group.svg
similarity index 100%
rename from render-compose-html/src/commonMain/composeResources/svg/group.svg
rename to render-web-common/src/commonMain/composeResources/svg/group.svg
diff --git a/render-compose-html/src/commonMain/composeResources/svg/house.svg b/render-web-common/src/commonMain/composeResources/svg/house.svg
similarity index 100%
rename from render-compose-html/src/commonMain/composeResources/svg/house.svg
rename to render-web-common/src/commonMain/composeResources/svg/house.svg
diff --git a/render-compose-html/src/commonMain/composeResources/svg/lock.svg b/render-web-common/src/commonMain/composeResources/svg/lock.svg
similarity index 100%
rename from render-compose-html/src/commonMain/composeResources/svg/lock.svg
rename to render-web-common/src/commonMain/composeResources/svg/lock.svg
diff --git a/render-compose-html/src/commonMain/composeResources/svg/lock_open.svg b/render-web-common/src/commonMain/composeResources/svg/lock_open.svg
similarity index 100%
rename from render-compose-html/src/commonMain/composeResources/svg/lock_open.svg
rename to render-web-common/src/commonMain/composeResources/svg/lock_open.svg
diff --git a/render-compose-html/src/commonMain/composeResources/svg/moon.svg b/render-web-common/src/commonMain/composeResources/svg/moon.svg
similarity index 100%
rename from render-compose-html/src/commonMain/composeResources/svg/moon.svg
rename to render-web-common/src/commonMain/composeResources/svg/moon.svg
diff --git a/render-compose-html/src/commonMain/composeResources/svg/movie.svg b/render-web-common/src/commonMain/composeResources/svg/movie.svg
similarity index 100%
rename from render-compose-html/src/commonMain/composeResources/svg/movie.svg
rename to render-web-common/src/commonMain/composeResources/svg/movie.svg
diff --git a/render-compose-html/src/commonMain/composeResources/svg/person.svg b/render-web-common/src/commonMain/composeResources/svg/person.svg
similarity index 100%
rename from render-compose-html/src/commonMain/composeResources/svg/person.svg
rename to render-web-common/src/commonMain/composeResources/svg/person.svg
diff --git a/render-compose-html/src/commonMain/composeResources/svg/rain.svg b/render-web-common/src/commonMain/composeResources/svg/rain.svg
similarity index 100%
rename from render-compose-html/src/commonMain/composeResources/svg/rain.svg
rename to render-web-common/src/commonMain/composeResources/svg/rain.svg
diff --git a/render-compose-html/src/commonMain/composeResources/svg/remove.svg b/render-web-common/src/commonMain/composeResources/svg/remove.svg
similarity index 100%
rename from render-compose-html/src/commonMain/composeResources/svg/remove.svg
rename to render-web-common/src/commonMain/composeResources/svg/remove.svg
diff --git a/render-compose-html/src/commonMain/composeResources/svg/sunshine.svg b/render-web-common/src/commonMain/composeResources/svg/sunshine.svg
similarity index 100%
rename from render-compose-html/src/commonMain/composeResources/svg/sunshine.svg
rename to render-web-common/src/commonMain/composeResources/svg/sunshine.svg
diff --git a/render-compose-html/src/commonMain/composeResources/svg/temperature.svg b/render-web-common/src/commonMain/composeResources/svg/temperature.svg
similarity index 100%
rename from render-compose-html/src/commonMain/composeResources/svg/temperature.svg
rename to render-web-common/src/commonMain/composeResources/svg/temperature.svg
diff --git a/render-compose-html/src/commonMain/composeResources/svg/unknown.svg b/render-web-common/src/commonMain/composeResources/svg/unknown.svg
similarity index 100%
rename from render-compose-html/src/commonMain/composeResources/svg/unknown.svg
rename to render-web-common/src/commonMain/composeResources/svg/unknown.svg
diff --git a/render-compose-html/src/commonMain/composeResources/svg/water.svg b/render-web-common/src/commonMain/composeResources/svg/water.svg
similarity index 100%
rename from render-compose-html/src/commonMain/composeResources/svg/water.svg
rename to render-web-common/src/commonMain/composeResources/svg/water.svg
diff --git a/render-web-common/src/commonMain/kotlin/ink/ui/render/web/FixedGridLayouts.kt b/render-web-common/src/commonMain/kotlin/ink/ui/render/web/FixedGridLayouts.kt
new file mode 100644
index 0000000..0136fec
--- /dev/null
+++ b/render-web-common/src/commonMain/kotlin/ink/ui/render/web/FixedGridLayouts.kt
@@ -0,0 +1,7 @@
+package ink.ui.render.web
+
+import ink.ui.structures.layouts.FixedGridLayout
+
+val FixedGridLayout.gridTemplateColumns: String get() {
+ return (0 until columns).joinToString(" ") { "auto" }
+}
diff --git a/render-static-html/src/main/java/ink/ui/render/statichtml/renderer/Sentiments.kt b/render-web-common/src/commonMain/kotlin/ink/ui/render/web/Sentiments.kt
similarity index 88%
rename from render-static-html/src/main/java/ink/ui/render/statichtml/renderer/Sentiments.kt
rename to render-web-common/src/commonMain/kotlin/ink/ui/render/web/Sentiments.kt
index 0dde080..c5fb2fc 100644
--- a/render-static-html/src/main/java/ink/ui/render/statichtml/renderer/Sentiments.kt
+++ b/render-web-common/src/commonMain/kotlin/ink/ui/render/web/Sentiments.kt
@@ -1,4 +1,4 @@
-package ink.ui.render.statichtml.renderer
+package ink.ui.render.web
import ink.ui.structures.Sentiment
diff --git a/render-static-html/src/main/java/ink/ui/render/statichtml/renderer/Symbols.kt b/render-web-common/src/commonMain/kotlin/ink/ui/render/web/Symbols.kt
similarity index 84%
rename from render-static-html/src/main/java/ink/ui/render/statichtml/renderer/Symbols.kt
rename to render-web-common/src/commonMain/kotlin/ink/ui/render/web/Symbols.kt
index 5999155..bfbd85d 100644
--- a/render-static-html/src/main/java/ink/ui/render/statichtml/renderer/Symbols.kt
+++ b/render-web-common/src/commonMain/kotlin/ink/ui/render/web/Symbols.kt
@@ -1,8 +1,8 @@
-package ink.ui.render.statichtml.renderer
+package ink.ui.render.web
import ink.ui.structures.Symbol
-internal const val PATH = "composeResources/com.inkapplications.ui.render_compose_html.generated.resources/svg"
+const val RESOURCE_SVG_PATH = "composeResources/com.inkapplications.ui.render_web_common.generated.resources/svg"
val Symbol.svgSrc: String get() = when (this) {
Symbol.Add -> "add.svg"
@@ -30,4 +30,4 @@ val Symbol.svgSrc: String get() = when (this) {
Symbol.Temperature -> "temperature.svg"
Symbol.Water -> "water.svg"
else -> "unknown.svg"
-}.let { "$PATH/$it" }
+}.let { "$RESOURCE_SVG_PATH/$it" }
diff --git a/sample-web/build.gradle.kts b/sample-web/build.gradle.kts
index e816a43..1cd28bf 100644
--- a/sample-web/build.gradle.kts
+++ b/sample-web/build.gradle.kts
@@ -38,7 +38,7 @@ tasks.register("buildStatic") {
}
copy {
staticResDir.createDirectory()
- from(projects.renderComposeHtml.dependencyProject.layout.projectDirectory.dir("src/commonMain/composeResources"))
+ from(projects.renderWebCommon.dependencyProject.layout.projectDirectory.dir("src/commonMain/composeResources"))
into(staticResDir)
}
}
diff --git a/sample-web/src/jsMain/resources/index.html b/sample-web/src/jsMain/resources/index.html
index fa908ec..f2b074c 100644
--- a/sample-web/src/jsMain/resources/index.html
+++ b/sample-web/src/jsMain/resources/index.html
@@ -3,7 +3,7 @@
Sample
-
+
diff --git a/sample-web/src/staticMain/Sample.inkui.kts b/sample-web/src/staticMain/Sample.inkui.kts
index 3e9e832..24516b2 100644
--- a/sample-web/src/staticMain/Sample.inkui.kts
+++ b/sample-web/src/staticMain/Sample.inkui.kts
@@ -14,6 +14,18 @@ addBody(
TextElement("Body Text", TextStyle.Body),
TextElement("Caption", TextStyle.Caption),
StatusIndicatorElement("Nominal Status", Sentiment.Nominal),
+ FormattedText {
+ link(url="javascript:void(0)") {
+ text("Formatted")
+ }
+ space()
+ strong {
+ text("Text")
+ emphasis {
+ text("!!!")
+ }
+ }
+ }
)
)
)
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 42d683f..4b56e48 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -5,6 +5,7 @@ rootProject.name = "ink-ui"
include("render-compose")
include("render-compose-html")
include("render-static-html")
+include("render-web-common")
include("structures")
include("sample-android")
include("sample-web")
diff --git a/structures/api/structures.api b/structures/api/structures.api
index 2993e39..818facb 100644
--- a/structures/api/structures.api
+++ b/structures/api/structures.api
@@ -149,6 +149,104 @@ public final class ink/ui/structures/elements/EmptyElement : ink/ui/structures/e
public fun toString ()Ljava/lang/String;
}
+public final class ink/ui/structures/elements/FormattedText : ink/ui/structures/elements/UiElement$Static {
+ public fun (Ljava/util/List;)V
+ public fun (Lkotlin/jvm/functions/Function1;)V
+ public final fun component1 ()Ljava/util/List;
+ public final fun copy (Ljava/util/List;)Link/ui/structures/elements/FormattedText;
+ public static synthetic fun copy$default (Link/ui/structures/elements/FormattedText;Ljava/util/List;ILjava/lang/Object;)Link/ui/structures/elements/FormattedText;
+ public fun equals (Ljava/lang/Object;)Z
+ public final fun getSpans ()Ljava/util/List;
+ public fun hashCode ()I
+ public final fun toPlainTextElement (Link/ui/structures/TextStyle;)Link/ui/structures/elements/TextElement;
+ public fun toString ()Ljava/lang/String;
+}
+
+public final class ink/ui/structures/elements/FormattedText$Builder {
+ public fun ()V
+ public fun (Ljava/util/List;)V
+ public synthetic fun (Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+ public final fun component1 ()Ljava/util/List;
+ public final fun copy (Ljava/util/List;)Link/ui/structures/elements/FormattedText$Builder;
+ public static synthetic fun copy$default (Link/ui/structures/elements/FormattedText$Builder;Ljava/util/List;ILjava/lang/Object;)Link/ui/structures/elements/FormattedText$Builder;
+ public final fun emphasis (Lkotlin/jvm/functions/Function1;)V
+ public fun equals (Ljava/lang/Object;)Z
+ public final fun getSpans ()Ljava/util/List;
+ public fun hashCode ()I
+ public final fun link (Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V
+ public final fun setSpans (Ljava/util/List;)V
+ public final fun space ()V
+ public final fun strong (Lkotlin/jvm/functions/Function1;)V
+ public final fun text (Ljava/lang/String;)V
+ public fun toString ()Ljava/lang/String;
+}
+
+public abstract interface class ink/ui/structures/elements/FormattedText$Span {
+ public abstract fun toPlainString ()Ljava/lang/String;
+}
+
+public abstract interface class ink/ui/structures/elements/FormattedText$Span$Composite : ink/ui/structures/elements/FormattedText$Span {
+ public abstract fun getInner ()Ljava/util/List;
+}
+
+public final class ink/ui/structures/elements/FormattedText$Span$Composite$DefaultImpls {
+ public static fun toPlainString (Link/ui/structures/elements/FormattedText$Span$Composite;)Ljava/lang/String;
+}
+
+public final class ink/ui/structures/elements/FormattedText$Span$DefaultImpls {
+ public static fun toPlainString (Link/ui/structures/elements/FormattedText$Span;)Ljava/lang/String;
+}
+
+public final class ink/ui/structures/elements/FormattedText$Span$Emphasis : ink/ui/structures/elements/FormattedText$Span$Composite {
+ public fun (Ljava/util/List;)V
+ public final fun component1 ()Ljava/util/List;
+ public final fun copy (Ljava/util/List;)Link/ui/structures/elements/FormattedText$Span$Emphasis;
+ public static synthetic fun copy$default (Link/ui/structures/elements/FormattedText$Span$Emphasis;Ljava/util/List;ILjava/lang/Object;)Link/ui/structures/elements/FormattedText$Span$Emphasis;
+ public fun equals (Ljava/lang/Object;)Z
+ public fun getInner ()Ljava/util/List;
+ public fun hashCode ()I
+ public fun toPlainString ()Ljava/lang/String;
+ public fun toString ()Ljava/lang/String;
+}
+
+public final class ink/ui/structures/elements/FormattedText$Span$Link : ink/ui/structures/elements/FormattedText$Span$Composite {
+ public fun (Ljava/util/List;Ljava/lang/String;)V
+ public final fun component1 ()Ljava/util/List;
+ public final fun component2 ()Ljava/lang/String;
+ public final fun copy (Ljava/util/List;Ljava/lang/String;)Link/ui/structures/elements/FormattedText$Span$Link;
+ public static synthetic fun copy$default (Link/ui/structures/elements/FormattedText$Span$Link;Ljava/util/List;Ljava/lang/String;ILjava/lang/Object;)Link/ui/structures/elements/FormattedText$Span$Link;
+ public fun equals (Ljava/lang/Object;)Z
+ public fun getInner ()Ljava/util/List;
+ public final fun getUrl ()Ljava/lang/String;
+ public fun hashCode ()I
+ public fun toPlainString ()Ljava/lang/String;
+ public fun toString ()Ljava/lang/String;
+}
+
+public final class ink/ui/structures/elements/FormattedText$Span$Strong : ink/ui/structures/elements/FormattedText$Span$Composite {
+ public fun (Ljava/util/List;)V
+ public final fun component1 ()Ljava/util/List;
+ public final fun copy (Ljava/util/List;)Link/ui/structures/elements/FormattedText$Span$Strong;
+ public static synthetic fun copy$default (Link/ui/structures/elements/FormattedText$Span$Strong;Ljava/util/List;ILjava/lang/Object;)Link/ui/structures/elements/FormattedText$Span$Strong;
+ public fun equals (Ljava/lang/Object;)Z
+ public fun getInner ()Ljava/util/List;
+ public fun hashCode ()I
+ public fun toPlainString ()Ljava/lang/String;
+ public fun toString ()Ljava/lang/String;
+}
+
+public final class ink/ui/structures/elements/FormattedText$Span$Text : ink/ui/structures/elements/FormattedText$Span {
+ public fun (Ljava/lang/String;)V
+ public final fun component1 ()Ljava/lang/String;
+ public final fun copy (Ljava/lang/String;)Link/ui/structures/elements/FormattedText$Span$Text;
+ public static synthetic fun copy$default (Link/ui/structures/elements/FormattedText$Span$Text;Ljava/lang/String;ILjava/lang/Object;)Link/ui/structures/elements/FormattedText$Span$Text;
+ public fun equals (Ljava/lang/Object;)Z
+ public final fun getText ()Ljava/lang/String;
+ public fun hashCode ()I
+ public fun toPlainString ()Ljava/lang/String;
+ public fun toString ()Ljava/lang/String;
+}
+
public final class ink/ui/structures/elements/IconElement : ink/ui/structures/elements/UiElement$Static {
public synthetic fun (Ljava/lang/String;Link/ui/structures/Sentiment;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public synthetic fun (Ljava/lang/String;Link/ui/structures/Sentiment;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
@@ -353,3 +451,35 @@ public final class ink/ui/structures/layouts/ScrollingListLayout : ink/ui/struct
public abstract interface class ink/ui/structures/layouts/UiLayout {
}
+public abstract interface class ink/ui/structures/render/RenderResult {
+}
+
+public final class ink/ui/structures/render/RenderResult$Failed : ink/ui/structures/render/RenderResult {
+ public fun (Ljava/lang/Throwable;)V
+ public final fun component1 ()Ljava/lang/Throwable;
+ public final fun copy (Ljava/lang/Throwable;)Link/ui/structures/render/RenderResult$Failed;
+ public static synthetic fun copy$default (Link/ui/structures/render/RenderResult$Failed;Ljava/lang/Throwable;ILjava/lang/Object;)Link/ui/structures/render/RenderResult$Failed;
+ public fun equals (Ljava/lang/Object;)Z
+ public final fun getException ()Ljava/lang/Throwable;
+ public fun hashCode ()I
+ public fun toString ()Ljava/lang/String;
+}
+
+public final class ink/ui/structures/render/RenderResult$Rendered : ink/ui/structures/render/RenderResult {
+ public static final field INSTANCE Link/ui/structures/render/RenderResult$Rendered;
+ public fun equals (Ljava/lang/Object;)Z
+ public fun hashCode ()I
+ public fun toString ()Ljava/lang/String;
+}
+
+public final class ink/ui/structures/render/RenderResult$Skipped : ink/ui/structures/render/RenderResult {
+ public static final field INSTANCE Link/ui/structures/render/RenderResult$Skipped;
+ public fun equals (Ljava/lang/Object;)Z
+ public fun hashCode ()I
+ public fun toString ()Ljava/lang/String;
+}
+
+public final class ink/ui/structures/render/RenderResultKt {
+ public static final fun renderCatching (Lkotlin/jvm/functions/Function0;)Link/ui/structures/render/RenderResult;
+}
+
diff --git a/structures/src/commonMain/kotlin/ink/ui/structures/elements/FormattedText.kt b/structures/src/commonMain/kotlin/ink/ui/structures/elements/FormattedText.kt
new file mode 100644
index 0000000..6cff0b4
--- /dev/null
+++ b/structures/src/commonMain/kotlin/ink/ui/structures/elements/FormattedText.kt
@@ -0,0 +1,71 @@
+package ink.ui.structures.elements
+
+import ink.ui.structures.TextStyle
+
+data class FormattedText(
+ val spans: List
+): UiElement.Static {
+ constructor(builder: FormattedText.Builder.() -> Unit): this(
+ spans = Builder().apply(builder).spans
+ )
+
+ fun toPlainTextElement(
+ style: TextStyle,
+ ): TextElement {
+ return TextElement(
+ text = spans.joinToString("") { span ->
+ when (span) {
+ is Span.Text -> span.text
+ is Span.Composite -> span.inner.joinToString("") { it.toPlainString() }
+ }
+ },
+ style = style,
+ )
+ }
+
+ sealed interface Span {
+ sealed interface Composite: Span {
+ val inner: List
+ }
+ data class Text(
+ val text: String,
+ ): Span
+ data class Strong(
+ override val inner: List,
+ ): Composite
+ data class Emphasis(
+ override val inner: List,
+ ): Composite
+ data class Link(
+ override val inner: List,
+ val url: String,
+ ): Composite
+
+ fun toPlainString(): String {
+ return when (this) {
+ is Text -> text
+ is Composite -> inner.joinToString("") { it.toPlainString() }
+ }
+ }
+ }
+
+ data class Builder(
+ var spans: MutableList = mutableListOf(),
+ ) {
+ fun text(text: String) {
+ spans.add(Span.Text(text))
+ }
+ fun strong(builder: Builder.() -> Unit) {
+ spans.add(Span.Strong(Builder().apply(builder).spans))
+ }
+ fun emphasis(builder: Builder.() -> Unit) {
+ spans.add(Span.Emphasis(Builder().apply(builder).spans))
+ }
+ fun link(url: String, builder: Builder.() -> Unit) {
+ spans.add(Span.Link(Builder().apply(builder).spans, url))
+ }
+ fun space() {
+ spans.add(Span.Text(" "))
+ }
+ }
+}
diff --git a/structures/src/commonMain/kotlin/ink/ui/structures/render/RenderResult.kt b/structures/src/commonMain/kotlin/ink/ui/structures/render/RenderResult.kt
new file mode 100644
index 0000000..2a47b22
--- /dev/null
+++ b/structures/src/commonMain/kotlin/ink/ui/structures/render/RenderResult.kt
@@ -0,0 +1,13 @@
+package ink.ui.structures.render
+
+sealed interface RenderResult {
+ data object Rendered: RenderResult
+ data object Skipped: RenderResult
+ data class Failed(val exception: Throwable): RenderResult
+}
+
+inline fun renderCatching(
+ block: () -> RenderResult,
+): RenderResult {
+ return runCatching(block).getOrElse { RenderResult.Failed(it) }
+}