diff --git a/.github/workflows/deploy_maven_central.yml b/.github/workflows/deploy_maven_central.yml index 0564b78..e0cb4d0 100644 --- a/.github/workflows/deploy_maven_central.yml +++ b/.github/workflows/deploy_maven_central.yml @@ -1,44 +1,44 @@ -# -#name: deploy maven central -# -#on: -# push: -# workflow_dispatch: -# -#jobs: -# test: -# if: github.ref != 'refs/heads/main' -# uses: ./.github/workflows/test.yml -# cd: -# if: github.ref == 'refs/heads/main' -# runs-on: ubuntu-latest -# -# steps: -# - uses: actions/checkout@v4 -# - name: Import GPG key -# uses: crazy-max/ghaction-import-gpg@v5 -# with: -# gpg_private_key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} -# passphrase: ${{ secrets.MAVEN_GPG_PASSPHRASE }} -# - name: Set up Java -# uses: actions/setup-java@v3 -# with: -# java-version: '17' -# distribution: 'temurin' -# - name: Make gradlew executable -# run: chmod +x ./gradlew -# - name: Validate Gradle wrapper -# uses: gradle/wrapper-validation-action@v1 -# - name: Publish package -# uses: gradle/gradle-build-action@v2 -# with: -# arguments: | -# -PmavenCentralUsername=${{ secrets.MAVEN_USERNAME }} -# -PmavenCentralPassword=${{ secrets.MAVEN_PASSWORD }} -# -PsigningInMemoryKeyId=${{ secrets.MAVEN_GPG_KEY_ID }} -# -PsigningInMemoryPassword=${{ secrets.MAVEN_GPG_PASSPHRASE }} -# allTests publishAndReleaseToMavenCentral -# env: -# MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} -# MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }} -###### + +name: deploy maven central + +on: + push: + workflow_dispatch: + +jobs: + test: + if: github.ref != 'refs/heads/main' + uses: ./.github/workflows/test.yml + cd: + if: github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Import GPG key + uses: crazy-max/ghaction-import-gpg@v5 + with: + gpg_private_key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} + passphrase: ${{ secrets.MAVEN_GPG_PASSPHRASE }} + - name: Set up Java + uses: actions/setup-java@v3 + with: + java-version: '17' + distribution: 'temurin' + - name: Make gradlew executable + run: chmod +x ./gradlew + - name: Validate Gradle wrapper + uses: gradle/wrapper-validation-action@v1 + - name: Publish package + uses: gradle/gradle-build-action@v2 + with: + arguments: | + -PmavenCentralUsername=${{ secrets.MAVEN_USERNAME }} + -PmavenCentralPassword=${{ secrets.MAVEN_PASSWORD }} + -PsigningInMemoryKeyId=${{ secrets.MAVEN_GPG_KEY_ID }} + -PsigningInMemoryPassword=${{ secrets.MAVEN_GPG_PASSPHRASE }} + allTests publishAndReleaseToMavenCentral + env: + MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} + MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }} +##### diff --git a/README.md b/README.md new file mode 100644 index 0000000..cfb319f --- /dev/null +++ b/README.md @@ -0,0 +1,128 @@ +# hakate + +## About + +* A state managing library for kotlin +* It can manage state with dependency + +### repository + +* https://central.sonatype.com/artifact/net.kigawa/hakate + +## Using + +### Requirement + +* kotlin + * jvm + * js + +### Getting Started + +#### 1. add to dependency + +pom.xml + +```pom.xml + + net.kigawa + renlin + {version} + +``` + +build.gradle.kts + +```build.gradle.kts +implementation("net.kigawa:renlin:{version}") +``` + +#### 2. write the code + +write a root component +```kotlin +class SampleComponent( + val name: String, + val sub: Sub, +) { + val root = div.component { + t("test root") + + // call subcomponent + sub.display { + } + + fragment { + div { + fragment { + p { + t("text") + } + } + } + } + sub.controller { + } + } +} + +``` + +write a subcomponent +```kotlin +class Sub( + dispatcher: StateDispatcher, +) { + val state: MutableState = dispatcher.newState("state") + + val display = div.component { + t("display") + div { + val value = state.useValue() + t("display1") + div { + t("display1-1") + p { + t("display1-1-1 $value") + } + } + } + } + val controller = div.component { + t("controller") + } + // fragment component + val test = fragment().component { } + val test1 = fragment().component { } + val test2 = fragment().component { } +} +``` + +set state +```kotlin +state.set("new value") +``` + +init endpoint +```kotlin +val root = document.getElementById("root") ?: throw Exception("Root not found") +val sub = Sub() +val sample = SampleComponent("sample", sub) +val dispatcher = HakateInitializer().newStateDispatcher() +Entrypoint(root).render(sample.root, dispatcher) +``` + +## Author + +* kigawa + * contact@kigawa.net + +# Making + +## Version + +### Example: 9.1.2 + +* **9**: major, destructive +* **1**: miner, new function +* **2**: miner, bug fix diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b453eeb..1f68ca8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,6 +3,7 @@ kotlin-version = "2.1.0" coroutines-version = "1.9.0" coroutines-test-version = "1.10.1" datetime-version = "0.6.1" +hakate-version = "3.3.0" nexus-publish = "2.0.0-rc-1" dokka = "1.9.20" vanniktech-maven-publish = "0.29.0" @@ -14,12 +15,11 @@ kotlin-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines-version" } kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "coroutines-test-version" } kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "datetime-version" } -kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin-version" } nexus-publish = { module = "io.github.gradle-nexus.publish-plugin:io.github.gradle-nexus.publish-plugin.gradle.plugin", version.ref = "nexus-publish" } +hakate = { module = "net.kigawa:hakate", version.ref = "hakate-version" } [plugins] -sonatype-central-upload = { id = "cl.franciscosolis.sonatype-central-upload", version = "1.0.3" } kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin-version" } vanniktech-maven-publish = { id = "com.vanniktech.maven.publish", version.ref = "vanniktech-maven-publish" } dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" } \ No newline at end of file diff --git a/renlin/build.gradle.kts b/renlin/build.gradle.kts index dfbc9b6..a45e5b1 100644 --- a/renlin/build.gradle.kts +++ b/renlin/build.gradle.kts @@ -38,6 +38,7 @@ kotlin { sourceSets["commonMain"].dependencies { implementation(libs.kotlinx.coroutines.core) implementation(libs.kotlin.stdlib) + implementation(libs.hakate) } sourceSets["commonTest"].dependencies { implementation(kotlin("test-common")) diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/Noting.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/Noting.kt new file mode 100644 index 0000000..1f0bd78 --- /dev/null +++ b/renlin/src/commonMain/kotlin/net/kigawa/renlin/Noting.kt @@ -0,0 +1,5 @@ +package net.kigawa.renlin + +import net.kigawa.renlin.category.ContentCategory + +interface NotingContent: ContentCategory \ No newline at end of file diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/category/ContentCategory.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/category/ContentCategory.kt new file mode 100644 index 0000000..be32cb2 --- /dev/null +++ b/renlin/src/commonMain/kotlin/net/kigawa/renlin/category/ContentCategory.kt @@ -0,0 +1,17 @@ +package net.kigawa.renlin.category + +interface ContentCategory { +// fun newContentDsl(): DSL +// fun component( +// block: DSL.() -> Unit, +// ): Component1, EmptyDsl> { +// return object : FragmentComponent() { +// override fun newDsl(): DSL { +// return newContentDsl() +// } +// }.component(block) +// } +} + +interface AllContentCategory : ContentCategory, FlowContent, PhrasingContent, FlowPhrasingIntersection +interface DslContentCategory> \ No newline at end of file diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/category/FlowContent.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/category/FlowContent.kt new file mode 100644 index 0000000..addb686 --- /dev/null +++ b/renlin/src/commonMain/kotlin/net/kigawa/renlin/category/FlowContent.kt @@ -0,0 +1,25 @@ +package net.kigawa.renlin.category + +import net.kigawa.renlin.Html +import net.kigawa.renlin.dsl.Dsl + + +interface FlowContent : ContentCategory { +// override fun newContentDsl(): FlowContentDsl { +// return FragmentDsl() +// } +} + +@Html +interface FlowContentDsl : + Dsl { + +// fun fragment(block: FlowContentDsl.() -> Unit) { +// object : FragmentComponent() { +// override fun newDsl(): FlowContentDsl { +// return FragmentDsl() +// } +// }.render(this, block) +// } +} + diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/category/FlowPhrasing.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/category/FlowPhrasing.kt new file mode 100644 index 0000000..5b13275 --- /dev/null +++ b/renlin/src/commonMain/kotlin/net/kigawa/renlin/category/FlowPhrasing.kt @@ -0,0 +1,5 @@ +package net.kigawa.renlin.category + +interface FlowPhrasingIntersection : FlowContent, PhrasingContent {} +interface FlowPhrasingDsl : + FlowContentDsl \ No newline at end of file diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/category/PhrasingContentDsl.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/category/PhrasingContentDsl.kt new file mode 100644 index 0000000..90df22b --- /dev/null +++ b/renlin/src/commonMain/kotlin/net/kigawa/renlin/category/PhrasingContentDsl.kt @@ -0,0 +1,15 @@ +package net.kigawa.renlin.category + +import net.kigawa.renlin.dsl.Dsl +import net.kigawa.renlin.tag.text + + +interface PhrasingContent : ContentCategory + + +fun Dsl.t(str: String, key: String? = null) { + text.render(this) { + this@render.key = key + this@render.text = str + } +} \ No newline at end of file diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/dsl/Dsl.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/dsl/Dsl.kt index ad42866..8d0e022 100644 --- a/renlin/src/commonMain/kotlin/net/kigawa/renlin/dsl/Dsl.kt +++ b/renlin/src/commonMain/kotlin/net/kigawa/renlin/dsl/Dsl.kt @@ -1,10 +1,27 @@ package net.kigawa.renlin.dsl +import net.kigawa.hakate.api.state.State import net.kigawa.renlin.Html -import net.kigawa.renlin.element.TagElement +import net.kigawa.renlin.category.ContentCategory +import net.kigawa.renlin.dsl.state.DslState +import net.kigawa.renlin.element.TagNode +import net.kigawa.renlin.tag.Fragment +import net.kigawa.renlin.tag.Tag +import net.kigawa.renlin.tag.component.SubComponent @Html -interface Dsl { - val element: TagElement +interface Dsl { var key: String? + var dslState: DslState? + fun subDsl(registeredDslData: RegisteredDslData) + fun mountDslState(state: DslState, registeredDslData: RegisteredDslData) + fun applyElement(element: TagNode) + val states: Set> + operator fun , DSL : Dsl<*>> SubComponent.invoke(block: DSL.() -> Unit) = + this.render(this@Dsl, block) + + val fragment: SubComponent, out Dsl> + get() = Fragment.create() + + fun State.useValue(): T } \ No newline at end of file diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/dsl/DslBase.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/dsl/DslBase.kt index 21cd032..ee74621 100644 --- a/renlin/src/commonMain/kotlin/net/kigawa/renlin/dsl/DslBase.kt +++ b/renlin/src/commonMain/kotlin/net/kigawa/renlin/dsl/DslBase.kt @@ -1,9 +1,47 @@ package net.kigawa.renlin.dsl -import net.kigawa.renlin.element.TagElement +import net.kigawa.hakate.api.state.State +import net.kigawa.renlin.category.ContentCategory +import net.kigawa.renlin.dsl.state.DslState +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid -abstract class DslBase( - override val element: TagElement, -) : Dsl { +abstract class DslBase : Dsl { + override var dslState: DslState? = null override var key: String? = null -} \ No newline at end of file + private val subDsls = mutableListOf() + override val states = mutableSetOf>() + + override fun subDsl(registeredDslData: RegisteredDslData) { + @OptIn(ExperimentalUuidApi::class) + if (registeredDslData.dsl.key == null) registeredDslData.dsl.key = Uuid.random().toString() + + val i = subDsls.indexOfFirst { it.dsl.key == registeredDslData.dsl.key } + if (i == -1) subDsls.add(registeredDslData) + else subDsls[i] = registeredDslData + + dslState?.let { + registeredDslData.dsl.mountDslState( + it.subDslState(registeredDslData.dsl.key!!, registeredDslData.component), registeredDslData + ) + } + } + + override fun mountDslState(state: DslState, registeredDslData: RegisteredDslData) { + dslState = state + subDsls.forEach { + it.dsl.mountDslState( + state.subDslState(it.dsl.key!!, it.component), it + ) + } + state.setSubDsls(subDsls) + state.applyDsl(this, registeredDslData) + } + + override fun State.useValue(): T { + states.add(this) + return this.currentValue() + } +} + + diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/dsl/EmptyDsl.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/dsl/EmptyDsl.kt index fd5685b..c45d73f 100644 --- a/renlin/src/commonMain/kotlin/net/kigawa/renlin/dsl/EmptyDsl.kt +++ b/renlin/src/commonMain/kotlin/net/kigawa/renlin/dsl/EmptyDsl.kt @@ -1,9 +1,12 @@ package net.kigawa.renlin.dsl -import net.kigawa.renlin.element.TagElement +import net.kigawa.renlin.NotingContent +import net.kigawa.renlin.element.TagNode -class EmptyDsl : Dsl { - override val element: TagElement - get() = throw IllegalArgumentException("EmptyDsl") +class EmptyDsl : DslBase(), Dsl { override var key: String? = null + + override fun applyElement(element: TagNode) { + throw IllegalStateException("EmptyDsl applyElement") + } } \ No newline at end of file diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/dsl/RegisteredDslData.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/dsl/RegisteredDslData.kt new file mode 100644 index 0000000..d9821ca --- /dev/null +++ b/renlin/src/commonMain/kotlin/net/kigawa/renlin/dsl/RegisteredDslData.kt @@ -0,0 +1,10 @@ +package net.kigawa.renlin.dsl + +import net.kigawa.renlin.tag.component.SubComponent + +data class RegisteredDslData( + val dsl: Dsl<*>, + val component: SubComponent<*, *>, + val reload: () -> Unit, +) { +} \ No newline at end of file diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/dsl/category/FlowContentDsl.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/dsl/category/FlowContentDsl.kt deleted file mode 100644 index 77b530f..0000000 --- a/renlin/src/commonMain/kotlin/net/kigawa/renlin/dsl/category/FlowContentDsl.kt +++ /dev/null @@ -1,18 +0,0 @@ -package net.kigawa.renlin.dsl.category - -import net.kigawa.renlin.Html -import net.kigawa.renlin.dsl.Dsl -import net.kigawa.renlin.tag.component.Component0 -import net.kigawa.renlin.tag.component.Component1 -import net.kigawa.renlin.tag.item.FlowContentItem - -@Html -interface FlowContentDsl : Dsl { - operator fun , DSL : Dsl> Component0.invoke(block: DSL.() -> Unit) = - this.render(this@FlowContentDsl, block) - - operator fun , DSL : Dsl, T> Component1.invoke( - arg1: T, block: DSL.(arg1: T) -> Unit, - ) = - this.render(arg1, block) -} \ No newline at end of file diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/dsl/category/PalpableContentDsl.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/dsl/category/PalpableContentDsl.kt deleted file mode 100644 index 3ac56cd..0000000 --- a/renlin/src/commonMain/kotlin/net/kigawa/renlin/dsl/category/PalpableContentDsl.kt +++ /dev/null @@ -1,6 +0,0 @@ -package net.kigawa.renlin.dsl.category - -import net.kigawa.renlin.dsl.Dsl - -interface PalpableContentDsl : Dsl { -} \ No newline at end of file diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/dsl/state/BasicDslStateBase.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/dsl/state/BasicDslStateBase.kt new file mode 100644 index 0000000..f1b0395 --- /dev/null +++ b/renlin/src/commonMain/kotlin/net/kigawa/renlin/dsl/state/BasicDslStateBase.kt @@ -0,0 +1,67 @@ +package net.kigawa.renlin.dsl.state + +import net.kigawa.hakate.api.state.StateContext +import net.kigawa.renlin.dsl.Dsl +import net.kigawa.renlin.dsl.RegisteredDslData +import net.kigawa.renlin.element.TagNode +import net.kigawa.renlin.tag.Tag +import net.kigawa.renlin.tag.component.SubComponent + +abstract class BasicDslStateBase( + protected val stateContext: StateContext, +) : DslState { + protected var subStates = mutableListOf() + abstract override val ownElement: TagNode? + + override fun subDslState(key: String, component: SubComponent<*, *>): DslState { + return subStates.firstOrNull { it.key == key } ?: SubBasicDslState( + key, this, component, stateContext.newStateContext() + ).also { + subStates.add(it) + } + } + + override fun setSubDsls(dsls: List) { + val newList = mutableListOf() + + dsls.forEach { registeredData -> + val newState = subStates.first { it.key == registeredData.dsl.key } + subStates.remove(newState) + newList.add(newState) + } + subStates.forEach { + it.remove() + } + subStates = newList + } + + fun getIndex(basicDslState: SubBasicDslState): Int { + var relativeIndex = 0 + for (subState in subStates) { + if (subState == basicDslState) break + relativeIndex += subState.getElements().size + } + return relativeIndex + } + + abstract fun setElements(index: Int, elements: List) + fun getElements(): List { + return ownElement?.let { + if (it.isEmpty) listOf() + else listOf(it) + } ?: subStates.flatMap { it.getElements() } + } + + fun remove() { + ownElement?.remove() + subStates.forEach { it.remove() } + } + + + override fun applyDsl(dsl: Dsl<*>, registeredDslData: RegisteredDslData) { + throw NotImplementedError("BasicDslState not implemented.") + } + + abstract fun newElement(tag: Tag<*>): TagNode + +} \ No newline at end of file diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/dsl/state/DslState.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/dsl/state/DslState.kt new file mode 100644 index 0000000..b1b446c --- /dev/null +++ b/renlin/src/commonMain/kotlin/net/kigawa/renlin/dsl/state/DslState.kt @@ -0,0 +1,14 @@ +package net.kigawa.renlin.dsl.state + +import net.kigawa.renlin.dsl.Dsl +import net.kigawa.renlin.dsl.RegisteredDslData +import net.kigawa.renlin.element.TagNode +import net.kigawa.renlin.tag.component.SubComponent + +interface DslState { + val ownElement: TagNode? + val latestRegisteredDslData: RegisteredDslData? + fun subDslState(key: String, second: SubComponent<*, *>): DslState + fun setSubDsls(dsls: List) + fun applyDsl(dsl: Dsl<*>, registeredDslData: RegisteredDslData) +} \ No newline at end of file diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/dsl/state/RootDslStateBase.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/dsl/state/RootDslStateBase.kt new file mode 100644 index 0000000..06a4701 --- /dev/null +++ b/renlin/src/commonMain/kotlin/net/kigawa/renlin/dsl/state/RootDslStateBase.kt @@ -0,0 +1,24 @@ +package net.kigawa.renlin.dsl.state + +import net.kigawa.hakate.api.state.StateContext +import net.kigawa.renlin.dsl.RegisteredDslData +import net.kigawa.renlin.element.TagNode +import net.kigawa.renlin.tag.Tag + +class RootDslStateBase( + override val ownElement: TagNode, stateContext: StateContext, +) : BasicDslStateBase(stateContext) { + + override fun newElement(tag: Tag<*>): TagNode { + return ownElement.newNode(tag) + } + + override fun setElements( + index: Int, elements: List, + ) { + ownElement.setNodes(index, elements) + } + + override val latestRegisteredDslData: RegisteredDslData? + get() = null +} \ No newline at end of file diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/dsl/state/SubBasicDslState.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/dsl/state/SubBasicDslState.kt new file mode 100644 index 0000000..8ddaccf --- /dev/null +++ b/renlin/src/commonMain/kotlin/net/kigawa/renlin/dsl/state/SubBasicDslState.kt @@ -0,0 +1,66 @@ +package net.kigawa.renlin.dsl.state + +import net.kigawa.hakate.api.multi.mergeState +import net.kigawa.hakate.api.state.State +import net.kigawa.hakate.api.state.StateContext +import net.kigawa.renlin.dsl.Dsl +import net.kigawa.renlin.dsl.RegisteredDslData +import net.kigawa.renlin.element.TagNode +import net.kigawa.renlin.tag.Tag +import net.kigawa.renlin.tag.component.SubComponent +import net.kigawa.renlin.tag.component.TagComponent + +class SubBasicDslState( + val key: String, + private val parent: BasicDslStateBase, + component: SubComponent<*, *>, + stateContext: StateContext, +) : BasicDslStateBase(stateContext), DslState { + override val ownElement = if (component is TagComponent<*>) { + parent.newElement(component.tag) + } else null + override var latestRegisteredDslData: RegisteredDslData? = null + var latestStateContext: StateContext? = null + + override fun applyDsl(dsl: Dsl<*>, registeredDslData: RegisteredDslData) { + latestRegisteredDslData = registeredDslData + val index = parent.getIndex(this) + if (ownElement != null) { + dsl.applyElement(ownElement) + parent.setElements(index, listOf(ownElement)) + } else { + parent.setElements(index, subStates.flatMap { it.getElements() }) + } + latestStateContext?.cancel() + stateContext.dispatch { + latestStateContext = this@dispatch + var result: State<*>? = null + dsl.states.forEach { + if (result == null) { + result = it + return@forEach + } + result = mergeState(result, it) + } + var first = true + result?.collect { + if (first) { + first = false + return@collect + } + registeredDslData.reload() + } + } + } + + override fun setElements(index: Int, elements: List) { + if (ownElement == null) { + val ownIndex = parent.getIndex(this) + parent.setElements(index + ownIndex, elements) + } else ownElement.setNodes(index, elements) + } + + override fun newElement(tag: Tag<*>): TagNode { + return ownElement?.newNode(tag) ?: parent.newElement(tag) + } +} \ No newline at end of file diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/element/TagElement.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/element/TagElement.kt deleted file mode 100644 index 4465f21..0000000 --- a/renlin/src/commonMain/kotlin/net/kigawa/renlin/element/TagElement.kt +++ /dev/null @@ -1,8 +0,0 @@ -package net.kigawa.renlin.element - -import net.kigawa.renlin.tag.Tag - -@Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING") -expect class TagElement { - fun appendChild(tag: Tag<*>): TagElement -} \ No newline at end of file diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/element/TagNode.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/element/TagNode.kt new file mode 100644 index 0000000..e6b85d9 --- /dev/null +++ b/renlin/src/commonMain/kotlin/net/kigawa/renlin/element/TagNode.kt @@ -0,0 +1,12 @@ +package net.kigawa.renlin.element + +import net.kigawa.renlin.tag.Tag + +@Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING") +expect interface TagNode { + val isEmpty: Boolean + fun setTextContent(text: String?) + fun newNode(tag: Tag<*>): TagNode + fun remove() + fun setNodes(index: Int, nodes: List) +} \ No newline at end of file diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/Div.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/Div.kt index 9662bb7..91ed264 100644 --- a/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/Div.kt +++ b/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/Div.kt @@ -1,26 +1,22 @@ package net.kigawa.renlin.tag -import net.kigawa.renlin.dsl.Dsl +import net.kigawa.renlin.category.FlowContent +import net.kigawa.renlin.category.FlowPhrasingDsl +import net.kigawa.renlin.category.FlowPhrasingIntersection import net.kigawa.renlin.dsl.DslBase -import net.kigawa.renlin.dsl.category.FlowContentDsl -import net.kigawa.renlin.dsl.category.PalpableContentDsl -import net.kigawa.renlin.element.TagElement -import net.kigawa.renlin.tag.component.TagComponent0 -import net.kigawa.renlin.tag.item.FlowContentItem - -class DivDsl( - element: TagElement, -) : DslBase(element), Dsl, FlowContentDsl, PalpableContentDsl { +import net.kigawa.renlin.dsl.Dsl +import net.kigawa.renlin.element.TagNode +import net.kigawa.renlin.tag.component.TagComponent1 +class DivDsl : + DslBase(), Dsl, FlowPhrasingDsl { + override fun applyElement(element: TagNode) { + } } -val div = TagComponent0(Div) +val div = TagComponent1(Div, ::DivDsl) -object Div : FlowContentItem, Tag { +object Div : Tag { override val name: String get() = "div" - - override fun newDsl(element: TagElement): DivDsl { - return DivDsl(element) - } } diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/Fragment.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/Fragment.kt new file mode 100644 index 0000000..08bedfc --- /dev/null +++ b/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/Fragment.kt @@ -0,0 +1,51 @@ +package net.kigawa.renlin.tag + +import net.kigawa.renlin.category.ContentCategory +import net.kigawa.renlin.dsl.DslBase +import net.kigawa.renlin.dsl.Dsl +import net.kigawa.renlin.element.TagNode +import net.kigawa.renlin.tag.component.SubComponent +import net.kigawa.renlin.tag.component.StructuredComponent + +object Fragment { + + + //fun > KClass.component( +// newDsl: () -> NEW_DSL, +// block: DSL.() -> Unit, +//): Component1 { +// return object : Component1 { +// override val tag: TAG +// get() = tag +// +// override fun newDsl(): NEW_DSL { +// return newDsl() +// } +// +// override fun render(parentDsl: TagDsl<*>, block: NEW_DSL.() -> Unit) { +// val newDsl = newDsl() +// newDsl.block() +// val baseDsl = this@Component1.newDsl() +// baseDsl.block() +// baseDsl.key = newDsl.key +// parentDsl.subDsl(baseDsl, this@Component1) +// } +// } +//} +// +//fun component(block: DSL.() -> Unit) = component(::EmptyDsl, block) + fun create() = + object : StructuredComponent, Dsl> { + override fun newDsl(): Dsl { + return object : DslBase() { + override fun applyElement(element: TagNode) { + } + } + } + } + +} + +fun fragment(): SubComponent, Dsl> { + return Fragment.create() +} diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/P.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/P.kt index f2c9d68..b264065 100644 --- a/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/P.kt +++ b/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/P.kt @@ -1,25 +1,22 @@ package net.kigawa.renlin.tag import net.kigawa.renlin.Html -import net.kigawa.renlin.dsl.Dsl +import net.kigawa.renlin.category.FlowContent +import net.kigawa.renlin.category.PhrasingContent import net.kigawa.renlin.dsl.DslBase -import net.kigawa.renlin.dsl.category.PalpableContentDsl -import net.kigawa.renlin.element.TagElement -import net.kigawa.renlin.tag.component.TagComponent0 -import net.kigawa.renlin.tag.item.FlowContentItem - -class PDsl(element: TagElement) : DslBase(element), Dsl, PalpableContentDsl { +import net.kigawa.renlin.dsl.Dsl +import net.kigawa.renlin.element.TagNode +import net.kigawa.renlin.tag.component.TagComponent1 +class PDsl() : DslBase(), Dsl { + override fun applyElement(element: TagNode) { + } } @Html -val p = TagComponent0(P) +val p = TagComponent1(P, ::PDsl) -object P : Tag, FlowContentItem { +object P : Tag { override val name: String get() = "p" - - override fun newDsl(element: TagElement): PDsl { - return PDsl(element) - } } diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/Tag.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/Tag.kt index e31ad85..ef25ede 100644 --- a/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/Tag.kt +++ b/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/Tag.kt @@ -1,9 +1,8 @@ package net.kigawa.renlin.tag -import net.kigawa.renlin.dsl.Dsl -import net.kigawa.renlin.element.TagElement +import net.kigawa.renlin.category.ContentCategory -interface Tag { +@Suppress("unused") +interface Tag { val name: String - fun newDsl(element: TagElement): DSL } \ No newline at end of file diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/TextTag.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/TextTag.kt new file mode 100644 index 0000000..c60fbad --- /dev/null +++ b/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/TextTag.kt @@ -0,0 +1,27 @@ +package net.kigawa.renlin.tag + +import net.kigawa.renlin.NotingContent +import net.kigawa.renlin.category.PhrasingContent +import net.kigawa.renlin.dsl.Dsl +import net.kigawa.renlin.dsl.DslBase +import net.kigawa.renlin.element.TagNode +import net.kigawa.renlin.tag.component.TagComponent1 + +class TextDsl : DslBase(), Dsl { + var text: String? = null + + operator fun String.unaryPlus() { + text = this + } + + override fun applyElement(element: TagNode) { + element.setTextContent(text) + } +} + +val text = TagComponent1(TextTag, ::TextDsl) + +object TextTag : Tag { + override val name: String + get() = "TextNodeTag" +} diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/Component.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/Component.kt new file mode 100644 index 0000000..771d2c5 --- /dev/null +++ b/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/Component.kt @@ -0,0 +1,4 @@ +package net.kigawa.renlin.tag.component + +interface Component { +} \ No newline at end of file diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/Component0.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/Component0.kt deleted file mode 100644 index 6163cc5..0000000 --- a/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/Component0.kt +++ /dev/null @@ -1,30 +0,0 @@ -package net.kigawa.renlin.tag.component - -import net.kigawa.renlin.Html -import net.kigawa.renlin.dsl.Dsl -import net.kigawa.renlin.dsl.EmptyDsl -import net.kigawa.renlin.tag.Tag - -@Html -interface Component0, DSL : Dsl> { - fun render(parentDsl: Dsl, block: DSL.() -> Unit) - - fun component( - newDsl: () -> NEW_DSL, - block: DSL.(dsl: NEW_DSL) -> Unit, - ): Component0 { - val parent = this - val parentBlock = block - return object : Component0 { - override fun render(parentDsl: Dsl, childBlock: NEW_DSL.() -> Unit) { - parent.render(parentDsl) { - val dsl = newDsl() - dsl.childBlock() - parentBlock(dsl) - } - } - } - } - - fun component(block: DSL.() -> Unit) = component(::EmptyDsl) { block() } -} \ No newline at end of file diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/Component1.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/Component1.kt deleted file mode 100644 index 2eadb6a..0000000 --- a/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/Component1.kt +++ /dev/null @@ -1,8 +0,0 @@ -package net.kigawa.renlin.tag.component - -import net.kigawa.renlin.dsl.Dsl -import net.kigawa.renlin.tag.Tag - -interface Component1, DSL : Dsl, T> { - fun render(arg1: T, block: DSL.(arg1: T) -> Unit) -} \ No newline at end of file diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/StructuredComponent.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/StructuredComponent.kt new file mode 100644 index 0000000..bfe2ffb --- /dev/null +++ b/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/StructuredComponent.kt @@ -0,0 +1,15 @@ +package net.kigawa.renlin.tag.component + +import net.kigawa.renlin.dsl.Dsl +import net.kigawa.renlin.dsl.RegisteredDslData +import net.kigawa.renlin.tag.Tag + +interface StructuredComponent, DSL : Dsl<*>> : SubComponent { + override fun render(parentDsl: Dsl<*>, block: DSL.() -> Unit) { + val dsl = newDsl() + dsl.block() + parentDsl.subDsl(RegisteredDslData(dsl, this) { + render(parentDsl, block) + }) + } +} \ No newline at end of file diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/SubComponent.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/SubComponent.kt new file mode 100644 index 0000000..a791077 --- /dev/null +++ b/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/SubComponent.kt @@ -0,0 +1,43 @@ +package net.kigawa.renlin.tag.component + +import net.kigawa.hakate.api.state.State +import net.kigawa.renlin.Html +import net.kigawa.renlin.category.ContentCategory +import net.kigawa.renlin.dsl.Dsl +import net.kigawa.renlin.dsl.EmptyDsl +import net.kigawa.renlin.dsl.RegisteredDslData +import net.kigawa.renlin.tag.Tag + +@Html +interface SubComponent, DSL : Dsl<*>> : Component { + fun newDsl(): DSL + fun render(parentDsl: Dsl<*>, block: DSL.() -> Unit) + + fun > component( + newDsl: () -> NEW_DSL, + block: DSL.(dsl: NEW_DSL) -> Unit, + ): SubComponent { + return object : SubComponent { + + override fun newDsl(): NEW_DSL { + return newDsl() + } + + override fun render(parentDsl: Dsl<*>, block: NEW_DSL.() -> Unit) { + val newDsl = newDsl() + newDsl.block() + val baseDsl = this@SubComponent.newDsl() + baseDsl.block(newDsl) + baseDsl.key = newDsl.key + parentDsl.subDsl(RegisteredDslData(object : Dsl by baseDsl { + override val states: Set> + get() = baseDsl.states + newDsl.states + }, this@SubComponent) { + render(parentDsl, block = block) + }) + } + } + } + + fun component(block: DSL.() -> Unit) = component(::EmptyDsl) { block } +} \ No newline at end of file diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/TagComponent.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/TagComponent.kt new file mode 100644 index 0000000..c3715c0 --- /dev/null +++ b/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/TagComponent.kt @@ -0,0 +1,7 @@ +package net.kigawa.renlin.tag.component + +import net.kigawa.renlin.tag.Tag + +interface TagComponent> : Component { + val tag: TAG +} \ No newline at end of file diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/TagComponent0.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/TagComponent0.kt deleted file mode 100644 index 9280b76..0000000 --- a/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/TagComponent0.kt +++ /dev/null @@ -1,14 +0,0 @@ -package net.kigawa.renlin.tag.component - -import net.kigawa.renlin.dsl.Dsl -import net.kigawa.renlin.tag.Tag - -class TagComponent0, DSL : Dsl>( - private val tag: TAG, -) : Component0 { - override fun render(parentDsl: Dsl, block: DSL.() -> Unit) { - val element = parentDsl.element.appendChild(tag) - val dsl = tag.newDsl(element) - dsl.block() - } -} \ No newline at end of file diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/TagComponent1.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/TagComponent1.kt new file mode 100644 index 0000000..2739850 --- /dev/null +++ b/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/TagComponent1.kt @@ -0,0 +1,14 @@ +package net.kigawa.renlin.tag.component + +import net.kigawa.renlin.dsl.Dsl +import net.kigawa.renlin.tag.Tag + +class TagComponent1, DSL : Dsl<*>>( + override val tag: TAG, + private val newDslFunc: () -> DSL, +) : SubComponent, TagComponent, StructuredComponent { + override fun newDsl(): DSL { + return newDslFunc() + } + +} \ No newline at end of file diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/item/FlowContentItem.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/item/FlowContentItem.kt deleted file mode 100644 index 5d3dd95..0000000 --- a/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/item/FlowContentItem.kt +++ /dev/null @@ -1,7 +0,0 @@ -package net.kigawa.renlin.tag.item - -import net.kigawa.renlin.dsl.Dsl -import net.kigawa.renlin.tag.Tag - -interface FlowContentItem : Tag { -} \ No newline at end of file diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/util/Util.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/util/Util.kt new file mode 100644 index 0000000..a183412 --- /dev/null +++ b/renlin/src/commonMain/kotlin/net/kigawa/renlin/util/Util.kt @@ -0,0 +1,5 @@ +package net.kigawa.renlin.util + +inline fun T.debug(vararg msgs: Any?) { + println("${this::class}: ${msgs.joinToString(separator = ", ")}") +} \ No newline at end of file diff --git a/renlin/src/jsMain/kotlin/net/kigawa/renlin/DomDsl.kt b/renlin/src/jsMain/kotlin/net/kigawa/renlin/DomDsl.kt deleted file mode 100644 index 0caee08..0000000 --- a/renlin/src/jsMain/kotlin/net/kigawa/renlin/DomDsl.kt +++ /dev/null @@ -1,9 +0,0 @@ -package net.kigawa.renlin - -import net.kigawa.renlin.dsl.Dsl -import net.kigawa.renlin.dsl.DslBase -import net.kigawa.renlin.element.TagElement -import org.w3c.dom.HTMLElement - -class DomDsl(htmlElement: HTMLElement) : DslBase(TagElement(htmlElement)), Dsl { -} \ No newline at end of file diff --git a/renlin/src/jsMain/kotlin/net/kigawa/renlin/Entrypoint.kt b/renlin/src/jsMain/kotlin/net/kigawa/renlin/Entrypoint.kt index 735765c..6a540b6 100644 --- a/renlin/src/jsMain/kotlin/net/kigawa/renlin/Entrypoint.kt +++ b/renlin/src/jsMain/kotlin/net/kigawa/renlin/Entrypoint.kt @@ -1,14 +1,18 @@ package net.kigawa.renlin +import net.kigawa.hakate.api.state.StateDispatcher +import net.kigawa.renlin.dsl.DomDsl import net.kigawa.renlin.dsl.EmptyDsl -import net.kigawa.renlin.tag.component.Component0 -import org.w3c.dom.HTMLElement +import net.kigawa.renlin.tag.component.SubComponent +import org.w3c.dom.Element class Entrypoint( - val element: HTMLElement, + val element: Element, ) { - fun render(component: Component0<*, EmptyDsl>) { - val dsl = DomDsl(element) - component.render(dsl) {} + fun render(component: SubComponent<*, EmptyDsl>, dispatcher: StateDispatcher) { + val dsl = DomDsl(element, dispatcher) + component.render(dsl) { + key = "root" + } } } \ No newline at end of file diff --git a/renlin/src/jsMain/kotlin/net/kigawa/renlin/dsl/DomDsl.kt b/renlin/src/jsMain/kotlin/net/kigawa/renlin/dsl/DomDsl.kt new file mode 100644 index 0000000..6ec4b8c --- /dev/null +++ b/renlin/src/jsMain/kotlin/net/kigawa/renlin/dsl/DomDsl.kt @@ -0,0 +1,17 @@ +package net.kigawa.renlin.dsl + +import net.kigawa.hakate.api.state.StateDispatcher +import net.kigawa.renlin.category.AllContentCategory +import net.kigawa.renlin.dsl.state.RootDslStateBase +import net.kigawa.renlin.element.DomTagElement +import net.kigawa.renlin.element.TagNode +import org.w3c.dom.Element + +class DomDsl(element: Element, dispatcher: StateDispatcher) : DslBase(), Dsl { + init { + dslState = RootDslStateBase(DomTagElement(element, null), dispatcher.newStateContext()) + } + + override fun applyElement(element: TagNode) { + } +} \ No newline at end of file diff --git a/renlin/src/jsMain/kotlin/net/kigawa/renlin/element/DomTagElement.kt b/renlin/src/jsMain/kotlin/net/kigawa/renlin/element/DomTagElement.kt new file mode 100644 index 0000000..bd1cd47 --- /dev/null +++ b/renlin/src/jsMain/kotlin/net/kigawa/renlin/element/DomTagElement.kt @@ -0,0 +1,45 @@ +package net.kigawa.renlin.element + +import kotlinx.browser.document +import net.kigawa.renlin.tag.Tag +import net.kigawa.renlin.tag.TextTag +import org.w3c.dom.Node +import org.w3c.dom.Text + +class DomTagElement( + override val node: Node, + private val parent: DomTagElement?, +) : TagNode { + override val isEmpty: Boolean + get() = if (node is Text) node.textContent == null else false + + override fun setTextContent(text: String?) { + if (node.textContent != text) node.textContent = text + } + + override fun newNode(tag: Tag<*>): TagNode { + return DomTagElement( + if (tag is TextTag) Text() else document.createElement(tag.name), + this + ) + } + + override fun remove() { + parent?.node?.removeChild(node) + } + + override fun setNodes( + index: Int, nodes: List, + ) { + var last: Node? = node.firstChild + repeat(index) { + last = last?.nextSibling + } + nodes.forEach { + if (it.node != last) { + node.insertBefore(it.node, last) + } + last = it.node.nextSibling + } + } +} \ No newline at end of file diff --git a/renlin/src/jsMain/kotlin/net/kigawa/renlin/element/TagElement.kt b/renlin/src/jsMain/kotlin/net/kigawa/renlin/element/TagElement.kt deleted file mode 100644 index fe7b1ed..0000000 --- a/renlin/src/jsMain/kotlin/net/kigawa/renlin/element/TagElement.kt +++ /dev/null @@ -1,16 +0,0 @@ -package net.kigawa.renlin.element - -import kotlinx.browser.document -import net.kigawa.renlin.tag.Tag -import org.w3c.dom.Element - -@Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING") -actual class TagElement( - private val htmlElement: Element, -) { - actual fun appendChild(tag: Tag<*>): TagElement { - val child = document.createElement(tag.name) - htmlElement.appendChild(child) - return TagElement(child) - } -} \ No newline at end of file diff --git a/renlin/src/jsMain/kotlin/net/kigawa/renlin/element/TagNode.kt b/renlin/src/jsMain/kotlin/net/kigawa/renlin/element/TagNode.kt new file mode 100644 index 0000000..87c58b7 --- /dev/null +++ b/renlin/src/jsMain/kotlin/net/kigawa/renlin/element/TagNode.kt @@ -0,0 +1,14 @@ +package net.kigawa.renlin.element + +import net.kigawa.renlin.tag.Tag +import org.w3c.dom.Node + +@Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING") +actual interface TagNode { + actual val isEmpty: Boolean + val node: Node + actual fun setTextContent(text: String?) + actual fun newNode(tag: Tag<*>): TagNode + actual fun remove() + actual fun setNodes(index: Int, nodes: List) +} \ No newline at end of file diff --git a/renlin/src/jsMain/kotlin/net/kigawa/renlin/util/Util.kt b/renlin/src/jsMain/kotlin/net/kigawa/renlin/util/Util.kt new file mode 100644 index 0000000..25c572d --- /dev/null +++ b/renlin/src/jsMain/kotlin/net/kigawa/renlin/util/Util.kt @@ -0,0 +1,8 @@ +package net.kigawa.renlin.util + +import org.w3c.dom.Element + + +fun Element.afterElement(element: Element) { + after(element) +} \ No newline at end of file diff --git a/renlin/src/jvmMain/kotlin/net/kigawa/renlin/element/TagElement.kt b/renlin/src/jvmMain/kotlin/net/kigawa/renlin/element/TagElement.kt deleted file mode 100644 index 227c78b..0000000 --- a/renlin/src/jvmMain/kotlin/net/kigawa/renlin/element/TagElement.kt +++ /dev/null @@ -1,10 +0,0 @@ -package net.kigawa.renlin.element - -import net.kigawa.renlin.tag.Tag - -@Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING") -actual class TagElement { - actual fun appendChild(tag: Tag<*>): TagElement { - TODO() - } -} \ No newline at end of file diff --git a/renlin/src/jvmMain/kotlin/net/kigawa/renlin/element/TagNode.kt b/renlin/src/jvmMain/kotlin/net/kigawa/renlin/element/TagNode.kt new file mode 100644 index 0000000..7bca34a --- /dev/null +++ b/renlin/src/jvmMain/kotlin/net/kigawa/renlin/element/TagNode.kt @@ -0,0 +1,12 @@ +package net.kigawa.renlin.element + +import net.kigawa.renlin.tag.Tag + +@Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING") +actual interface TagNode { + actual val isEmpty: Boolean + actual fun setTextContent(text: String?) + actual fun newNode(tag: Tag<*>): TagNode + actual fun remove() + actual fun setNodes(index: Int, nodes: List) +} \ No newline at end of file diff --git a/sample/build.gradle.kts b/sample/build.gradle.kts index 7f2765e..aff80e2 100644 --- a/sample/build.gradle.kts +++ b/sample/build.gradle.kts @@ -31,6 +31,8 @@ kotlin { } sourceSets["commonMain"].dependencies { implementation(project(":renlin")) + implementation(libs.hakate) + implementation(libs.kotlinx.coroutines.core) } sourceSets["commonTest"].dependencies { implementation(kotlin("test-common")) diff --git a/sample/src/commonMain/kotlin/net/kigawa/renlin/sample/SampleComponent.kt b/sample/src/commonMain/kotlin/net/kigawa/renlin/sample/SampleComponent.kt index 7ac9753..6866efe 100644 --- a/sample/src/commonMain/kotlin/net/kigawa/renlin/sample/SampleComponent.kt +++ b/sample/src/commonMain/kotlin/net/kigawa/renlin/sample/SampleComponent.kt @@ -1,16 +1,54 @@ package net.kigawa.renlin.sample +import net.kigawa.renlin.category.t import net.kigawa.renlin.tag.div import net.kigawa.renlin.tag.p +import net.kigawa.renlin.tag.text class SampleComponent( val name: String, val sub: Sub, ) { + var update: (Int) -> Unit = {} val root = div.component { + key = "key root" + t("test root") + div { + key = "uuid 1" + text { + key = "uuid 1-1" + +"repeat " + } + } + sub.display { + key = "uuid 2" + } + + fragment { + div { + fragment { + p { + t("") + } + } + p { +// +"aaaa" + } + } + } +// fragment { + sub.display { + key = "uuid 3" + } +// } + sub.controller { + key = "uuid 4" + } p { +// key = "uuid 5" } - sub.display {} - sub.controller {} + sub.test {} + sub.test1 {} + sub.test2 {} } } diff --git a/sample/src/commonMain/kotlin/net/kigawa/renlin/sample/Sub.kt b/sample/src/commonMain/kotlin/net/kigawa/renlin/sample/Sub.kt index 41abc40..bc8d3de 100644 --- a/sample/src/commonMain/kotlin/net/kigawa/renlin/sample/Sub.kt +++ b/sample/src/commonMain/kotlin/net/kigawa/renlin/sample/Sub.kt @@ -1,18 +1,52 @@ package net.kigawa.renlin.sample +import net.kigawa.hakate.api.HakateInitializer +import net.kigawa.hakate.api.state.MutableState +import net.kigawa.renlin.category.FlowContent +import net.kigawa.renlin.category.FlowPhrasingIntersection +import net.kigawa.renlin.category.PhrasingContent +import net.kigawa.renlin.category.t import net.kigawa.renlin.tag.div +import net.kigawa.renlin.tag.fragment import net.kigawa.renlin.tag.p class Sub { + val state: MutableState = HakateInitializer().newStateDispatcher().newState("state") + val display = div.component { + t("display") + key = "uuid aaaaaaaaa" div { + val value = state.useValue() + key = "key display1 div" + t("display1", key = "key display1") div { + t("display1-1", key = "key display1-1") + key = "key display1-1 div" p { - + t("display1-1-1 $value", key = "key display1-1-1") + key = "key display1-1-1 p" } } } + div { + t("display2") + key = "uuid aawaaaaaaaad" + div { + t("display2-1") + key = "uuid aadaaaaaaa" + } + } + div { + t("display3") + key = "uuid aawaaaaaaaa" + } } val controller = div.component { + t("controller") + key = "uuid aaadaadadsaaaa" } + val test = fragment().component { } + val test1 = fragment().component { } + val test2 = fragment().component { } } \ No newline at end of file diff --git a/sample/src/jsMain/kotlin/net/kigawa/renlin/sample/Main.kt b/sample/src/jsMain/kotlin/net/kigawa/renlin/sample/Main.kt index 8ff02c8..217e30d 100644 --- a/sample/src/jsMain/kotlin/net/kigawa/renlin/sample/Main.kt +++ b/sample/src/jsMain/kotlin/net/kigawa/renlin/sample/Main.kt @@ -1,12 +1,24 @@ package net.kigawa.renlin.sample import kotlinx.browser.document +import kotlinx.browser.window +import net.kigawa.hakate.api.HakateInitializer import net.kigawa.renlin.Entrypoint -import org.w3c.dom.HTMLElement fun main() { val root = document.getElementById("root") ?: throw Exception("Root not found") - if (root !is HTMLElement) throw Exception("Root not html element") - val sample = SampleComponent("sample", Sub()) - Entrypoint(root).render(sample.root) + val sub = Sub() + val sample = SampleComponent("sample", sub) + val dispatcher = HakateInitializer().newStateDispatcher() + Entrypoint(root).render(sample.root, dispatcher) + var i = 0 + window.setInterval( + { + i++ + sample.update(i) + sub.state.set("state $i") + }, + 1000, 10000 + ) + } \ No newline at end of file
(P) +val p = TagComponent1
(P, ::PDsl) -object P : Tag, FlowContentItem { +object P : Tag { override val name: String get() = "p" - - override fun newDsl(element: TagElement): PDsl { - return PDsl(element) - } } diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/Tag.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/Tag.kt index e31ad85..ef25ede 100644 --- a/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/Tag.kt +++ b/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/Tag.kt @@ -1,9 +1,8 @@ package net.kigawa.renlin.tag -import net.kigawa.renlin.dsl.Dsl -import net.kigawa.renlin.element.TagElement +import net.kigawa.renlin.category.ContentCategory -interface Tag { +@Suppress("unused") +interface Tag { val name: String - fun newDsl(element: TagElement): DSL } \ No newline at end of file diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/TextTag.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/TextTag.kt new file mode 100644 index 0000000..c60fbad --- /dev/null +++ b/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/TextTag.kt @@ -0,0 +1,27 @@ +package net.kigawa.renlin.tag + +import net.kigawa.renlin.NotingContent +import net.kigawa.renlin.category.PhrasingContent +import net.kigawa.renlin.dsl.Dsl +import net.kigawa.renlin.dsl.DslBase +import net.kigawa.renlin.element.TagNode +import net.kigawa.renlin.tag.component.TagComponent1 + +class TextDsl : DslBase(), Dsl { + var text: String? = null + + operator fun String.unaryPlus() { + text = this + } + + override fun applyElement(element: TagNode) { + element.setTextContent(text) + } +} + +val text = TagComponent1(TextTag, ::TextDsl) + +object TextTag : Tag { + override val name: String + get() = "TextNodeTag" +} diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/Component.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/Component.kt new file mode 100644 index 0000000..771d2c5 --- /dev/null +++ b/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/Component.kt @@ -0,0 +1,4 @@ +package net.kigawa.renlin.tag.component + +interface Component { +} \ No newline at end of file diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/Component0.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/Component0.kt deleted file mode 100644 index 6163cc5..0000000 --- a/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/Component0.kt +++ /dev/null @@ -1,30 +0,0 @@ -package net.kigawa.renlin.tag.component - -import net.kigawa.renlin.Html -import net.kigawa.renlin.dsl.Dsl -import net.kigawa.renlin.dsl.EmptyDsl -import net.kigawa.renlin.tag.Tag - -@Html -interface Component0, DSL : Dsl> { - fun render(parentDsl: Dsl, block: DSL.() -> Unit) - - fun component( - newDsl: () -> NEW_DSL, - block: DSL.(dsl: NEW_DSL) -> Unit, - ): Component0 { - val parent = this - val parentBlock = block - return object : Component0 { - override fun render(parentDsl: Dsl, childBlock: NEW_DSL.() -> Unit) { - parent.render(parentDsl) { - val dsl = newDsl() - dsl.childBlock() - parentBlock(dsl) - } - } - } - } - - fun component(block: DSL.() -> Unit) = component(::EmptyDsl) { block() } -} \ No newline at end of file diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/Component1.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/Component1.kt deleted file mode 100644 index 2eadb6a..0000000 --- a/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/Component1.kt +++ /dev/null @@ -1,8 +0,0 @@ -package net.kigawa.renlin.tag.component - -import net.kigawa.renlin.dsl.Dsl -import net.kigawa.renlin.tag.Tag - -interface Component1, DSL : Dsl, T> { - fun render(arg1: T, block: DSL.(arg1: T) -> Unit) -} \ No newline at end of file diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/StructuredComponent.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/StructuredComponent.kt new file mode 100644 index 0000000..bfe2ffb --- /dev/null +++ b/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/StructuredComponent.kt @@ -0,0 +1,15 @@ +package net.kigawa.renlin.tag.component + +import net.kigawa.renlin.dsl.Dsl +import net.kigawa.renlin.dsl.RegisteredDslData +import net.kigawa.renlin.tag.Tag + +interface StructuredComponent, DSL : Dsl<*>> : SubComponent { + override fun render(parentDsl: Dsl<*>, block: DSL.() -> Unit) { + val dsl = newDsl() + dsl.block() + parentDsl.subDsl(RegisteredDslData(dsl, this) { + render(parentDsl, block) + }) + } +} \ No newline at end of file diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/SubComponent.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/SubComponent.kt new file mode 100644 index 0000000..a791077 --- /dev/null +++ b/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/SubComponent.kt @@ -0,0 +1,43 @@ +package net.kigawa.renlin.tag.component + +import net.kigawa.hakate.api.state.State +import net.kigawa.renlin.Html +import net.kigawa.renlin.category.ContentCategory +import net.kigawa.renlin.dsl.Dsl +import net.kigawa.renlin.dsl.EmptyDsl +import net.kigawa.renlin.dsl.RegisteredDslData +import net.kigawa.renlin.tag.Tag + +@Html +interface SubComponent, DSL : Dsl<*>> : Component { + fun newDsl(): DSL + fun render(parentDsl: Dsl<*>, block: DSL.() -> Unit) + + fun > component( + newDsl: () -> NEW_DSL, + block: DSL.(dsl: NEW_DSL) -> Unit, + ): SubComponent { + return object : SubComponent { + + override fun newDsl(): NEW_DSL { + return newDsl() + } + + override fun render(parentDsl: Dsl<*>, block: NEW_DSL.() -> Unit) { + val newDsl = newDsl() + newDsl.block() + val baseDsl = this@SubComponent.newDsl() + baseDsl.block(newDsl) + baseDsl.key = newDsl.key + parentDsl.subDsl(RegisteredDslData(object : Dsl by baseDsl { + override val states: Set> + get() = baseDsl.states + newDsl.states + }, this@SubComponent) { + render(parentDsl, block = block) + }) + } + } + } + + fun component(block: DSL.() -> Unit) = component(::EmptyDsl) { block } +} \ No newline at end of file diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/TagComponent.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/TagComponent.kt new file mode 100644 index 0000000..c3715c0 --- /dev/null +++ b/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/TagComponent.kt @@ -0,0 +1,7 @@ +package net.kigawa.renlin.tag.component + +import net.kigawa.renlin.tag.Tag + +interface TagComponent> : Component { + val tag: TAG +} \ No newline at end of file diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/TagComponent0.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/TagComponent0.kt deleted file mode 100644 index 9280b76..0000000 --- a/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/TagComponent0.kt +++ /dev/null @@ -1,14 +0,0 @@ -package net.kigawa.renlin.tag.component - -import net.kigawa.renlin.dsl.Dsl -import net.kigawa.renlin.tag.Tag - -class TagComponent0, DSL : Dsl>( - private val tag: TAG, -) : Component0 { - override fun render(parentDsl: Dsl, block: DSL.() -> Unit) { - val element = parentDsl.element.appendChild(tag) - val dsl = tag.newDsl(element) - dsl.block() - } -} \ No newline at end of file diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/TagComponent1.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/TagComponent1.kt new file mode 100644 index 0000000..2739850 --- /dev/null +++ b/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/component/TagComponent1.kt @@ -0,0 +1,14 @@ +package net.kigawa.renlin.tag.component + +import net.kigawa.renlin.dsl.Dsl +import net.kigawa.renlin.tag.Tag + +class TagComponent1, DSL : Dsl<*>>( + override val tag: TAG, + private val newDslFunc: () -> DSL, +) : SubComponent, TagComponent, StructuredComponent { + override fun newDsl(): DSL { + return newDslFunc() + } + +} \ No newline at end of file diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/item/FlowContentItem.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/item/FlowContentItem.kt deleted file mode 100644 index 5d3dd95..0000000 --- a/renlin/src/commonMain/kotlin/net/kigawa/renlin/tag/item/FlowContentItem.kt +++ /dev/null @@ -1,7 +0,0 @@ -package net.kigawa.renlin.tag.item - -import net.kigawa.renlin.dsl.Dsl -import net.kigawa.renlin.tag.Tag - -interface FlowContentItem : Tag { -} \ No newline at end of file diff --git a/renlin/src/commonMain/kotlin/net/kigawa/renlin/util/Util.kt b/renlin/src/commonMain/kotlin/net/kigawa/renlin/util/Util.kt new file mode 100644 index 0000000..a183412 --- /dev/null +++ b/renlin/src/commonMain/kotlin/net/kigawa/renlin/util/Util.kt @@ -0,0 +1,5 @@ +package net.kigawa.renlin.util + +inline fun T.debug(vararg msgs: Any?) { + println("${this::class}: ${msgs.joinToString(separator = ", ")}") +} \ No newline at end of file diff --git a/renlin/src/jsMain/kotlin/net/kigawa/renlin/DomDsl.kt b/renlin/src/jsMain/kotlin/net/kigawa/renlin/DomDsl.kt deleted file mode 100644 index 0caee08..0000000 --- a/renlin/src/jsMain/kotlin/net/kigawa/renlin/DomDsl.kt +++ /dev/null @@ -1,9 +0,0 @@ -package net.kigawa.renlin - -import net.kigawa.renlin.dsl.Dsl -import net.kigawa.renlin.dsl.DslBase -import net.kigawa.renlin.element.TagElement -import org.w3c.dom.HTMLElement - -class DomDsl(htmlElement: HTMLElement) : DslBase(TagElement(htmlElement)), Dsl { -} \ No newline at end of file diff --git a/renlin/src/jsMain/kotlin/net/kigawa/renlin/Entrypoint.kt b/renlin/src/jsMain/kotlin/net/kigawa/renlin/Entrypoint.kt index 735765c..6a540b6 100644 --- a/renlin/src/jsMain/kotlin/net/kigawa/renlin/Entrypoint.kt +++ b/renlin/src/jsMain/kotlin/net/kigawa/renlin/Entrypoint.kt @@ -1,14 +1,18 @@ package net.kigawa.renlin +import net.kigawa.hakate.api.state.StateDispatcher +import net.kigawa.renlin.dsl.DomDsl import net.kigawa.renlin.dsl.EmptyDsl -import net.kigawa.renlin.tag.component.Component0 -import org.w3c.dom.HTMLElement +import net.kigawa.renlin.tag.component.SubComponent +import org.w3c.dom.Element class Entrypoint( - val element: HTMLElement, + val element: Element, ) { - fun render(component: Component0<*, EmptyDsl>) { - val dsl = DomDsl(element) - component.render(dsl) {} + fun render(component: SubComponent<*, EmptyDsl>, dispatcher: StateDispatcher) { + val dsl = DomDsl(element, dispatcher) + component.render(dsl) { + key = "root" + } } } \ No newline at end of file diff --git a/renlin/src/jsMain/kotlin/net/kigawa/renlin/dsl/DomDsl.kt b/renlin/src/jsMain/kotlin/net/kigawa/renlin/dsl/DomDsl.kt new file mode 100644 index 0000000..6ec4b8c --- /dev/null +++ b/renlin/src/jsMain/kotlin/net/kigawa/renlin/dsl/DomDsl.kt @@ -0,0 +1,17 @@ +package net.kigawa.renlin.dsl + +import net.kigawa.hakate.api.state.StateDispatcher +import net.kigawa.renlin.category.AllContentCategory +import net.kigawa.renlin.dsl.state.RootDslStateBase +import net.kigawa.renlin.element.DomTagElement +import net.kigawa.renlin.element.TagNode +import org.w3c.dom.Element + +class DomDsl(element: Element, dispatcher: StateDispatcher) : DslBase(), Dsl { + init { + dslState = RootDslStateBase(DomTagElement(element, null), dispatcher.newStateContext()) + } + + override fun applyElement(element: TagNode) { + } +} \ No newline at end of file diff --git a/renlin/src/jsMain/kotlin/net/kigawa/renlin/element/DomTagElement.kt b/renlin/src/jsMain/kotlin/net/kigawa/renlin/element/DomTagElement.kt new file mode 100644 index 0000000..bd1cd47 --- /dev/null +++ b/renlin/src/jsMain/kotlin/net/kigawa/renlin/element/DomTagElement.kt @@ -0,0 +1,45 @@ +package net.kigawa.renlin.element + +import kotlinx.browser.document +import net.kigawa.renlin.tag.Tag +import net.kigawa.renlin.tag.TextTag +import org.w3c.dom.Node +import org.w3c.dom.Text + +class DomTagElement( + override val node: Node, + private val parent: DomTagElement?, +) : TagNode { + override val isEmpty: Boolean + get() = if (node is Text) node.textContent == null else false + + override fun setTextContent(text: String?) { + if (node.textContent != text) node.textContent = text + } + + override fun newNode(tag: Tag<*>): TagNode { + return DomTagElement( + if (tag is TextTag) Text() else document.createElement(tag.name), + this + ) + } + + override fun remove() { + parent?.node?.removeChild(node) + } + + override fun setNodes( + index: Int, nodes: List, + ) { + var last: Node? = node.firstChild + repeat(index) { + last = last?.nextSibling + } + nodes.forEach { + if (it.node != last) { + node.insertBefore(it.node, last) + } + last = it.node.nextSibling + } + } +} \ No newline at end of file diff --git a/renlin/src/jsMain/kotlin/net/kigawa/renlin/element/TagElement.kt b/renlin/src/jsMain/kotlin/net/kigawa/renlin/element/TagElement.kt deleted file mode 100644 index fe7b1ed..0000000 --- a/renlin/src/jsMain/kotlin/net/kigawa/renlin/element/TagElement.kt +++ /dev/null @@ -1,16 +0,0 @@ -package net.kigawa.renlin.element - -import kotlinx.browser.document -import net.kigawa.renlin.tag.Tag -import org.w3c.dom.Element - -@Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING") -actual class TagElement( - private val htmlElement: Element, -) { - actual fun appendChild(tag: Tag<*>): TagElement { - val child = document.createElement(tag.name) - htmlElement.appendChild(child) - return TagElement(child) - } -} \ No newline at end of file diff --git a/renlin/src/jsMain/kotlin/net/kigawa/renlin/element/TagNode.kt b/renlin/src/jsMain/kotlin/net/kigawa/renlin/element/TagNode.kt new file mode 100644 index 0000000..87c58b7 --- /dev/null +++ b/renlin/src/jsMain/kotlin/net/kigawa/renlin/element/TagNode.kt @@ -0,0 +1,14 @@ +package net.kigawa.renlin.element + +import net.kigawa.renlin.tag.Tag +import org.w3c.dom.Node + +@Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING") +actual interface TagNode { + actual val isEmpty: Boolean + val node: Node + actual fun setTextContent(text: String?) + actual fun newNode(tag: Tag<*>): TagNode + actual fun remove() + actual fun setNodes(index: Int, nodes: List) +} \ No newline at end of file diff --git a/renlin/src/jsMain/kotlin/net/kigawa/renlin/util/Util.kt b/renlin/src/jsMain/kotlin/net/kigawa/renlin/util/Util.kt new file mode 100644 index 0000000..25c572d --- /dev/null +++ b/renlin/src/jsMain/kotlin/net/kigawa/renlin/util/Util.kt @@ -0,0 +1,8 @@ +package net.kigawa.renlin.util + +import org.w3c.dom.Element + + +fun Element.afterElement(element: Element) { + after(element) +} \ No newline at end of file diff --git a/renlin/src/jvmMain/kotlin/net/kigawa/renlin/element/TagElement.kt b/renlin/src/jvmMain/kotlin/net/kigawa/renlin/element/TagElement.kt deleted file mode 100644 index 227c78b..0000000 --- a/renlin/src/jvmMain/kotlin/net/kigawa/renlin/element/TagElement.kt +++ /dev/null @@ -1,10 +0,0 @@ -package net.kigawa.renlin.element - -import net.kigawa.renlin.tag.Tag - -@Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING") -actual class TagElement { - actual fun appendChild(tag: Tag<*>): TagElement { - TODO() - } -} \ No newline at end of file diff --git a/renlin/src/jvmMain/kotlin/net/kigawa/renlin/element/TagNode.kt b/renlin/src/jvmMain/kotlin/net/kigawa/renlin/element/TagNode.kt new file mode 100644 index 0000000..7bca34a --- /dev/null +++ b/renlin/src/jvmMain/kotlin/net/kigawa/renlin/element/TagNode.kt @@ -0,0 +1,12 @@ +package net.kigawa.renlin.element + +import net.kigawa.renlin.tag.Tag + +@Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING") +actual interface TagNode { + actual val isEmpty: Boolean + actual fun setTextContent(text: String?) + actual fun newNode(tag: Tag<*>): TagNode + actual fun remove() + actual fun setNodes(index: Int, nodes: List) +} \ No newline at end of file diff --git a/sample/build.gradle.kts b/sample/build.gradle.kts index 7f2765e..aff80e2 100644 --- a/sample/build.gradle.kts +++ b/sample/build.gradle.kts @@ -31,6 +31,8 @@ kotlin { } sourceSets["commonMain"].dependencies { implementation(project(":renlin")) + implementation(libs.hakate) + implementation(libs.kotlinx.coroutines.core) } sourceSets["commonTest"].dependencies { implementation(kotlin("test-common")) diff --git a/sample/src/commonMain/kotlin/net/kigawa/renlin/sample/SampleComponent.kt b/sample/src/commonMain/kotlin/net/kigawa/renlin/sample/SampleComponent.kt index 7ac9753..6866efe 100644 --- a/sample/src/commonMain/kotlin/net/kigawa/renlin/sample/SampleComponent.kt +++ b/sample/src/commonMain/kotlin/net/kigawa/renlin/sample/SampleComponent.kt @@ -1,16 +1,54 @@ package net.kigawa.renlin.sample +import net.kigawa.renlin.category.t import net.kigawa.renlin.tag.div import net.kigawa.renlin.tag.p +import net.kigawa.renlin.tag.text class SampleComponent( val name: String, val sub: Sub, ) { + var update: (Int) -> Unit = {} val root = div.component { + key = "key root" + t("test root") + div { + key = "uuid 1" + text { + key = "uuid 1-1" + +"repeat " + } + } + sub.display { + key = "uuid 2" + } + + fragment { + div { + fragment { + p { + t("") + } + } + p { +// +"aaaa" + } + } + } +// fragment { + sub.display { + key = "uuid 3" + } +// } + sub.controller { + key = "uuid 4" + } p { +// key = "uuid 5" } - sub.display {} - sub.controller {} + sub.test {} + sub.test1 {} + sub.test2 {} } } diff --git a/sample/src/commonMain/kotlin/net/kigawa/renlin/sample/Sub.kt b/sample/src/commonMain/kotlin/net/kigawa/renlin/sample/Sub.kt index 41abc40..bc8d3de 100644 --- a/sample/src/commonMain/kotlin/net/kigawa/renlin/sample/Sub.kt +++ b/sample/src/commonMain/kotlin/net/kigawa/renlin/sample/Sub.kt @@ -1,18 +1,52 @@ package net.kigawa.renlin.sample +import net.kigawa.hakate.api.HakateInitializer +import net.kigawa.hakate.api.state.MutableState +import net.kigawa.renlin.category.FlowContent +import net.kigawa.renlin.category.FlowPhrasingIntersection +import net.kigawa.renlin.category.PhrasingContent +import net.kigawa.renlin.category.t import net.kigawa.renlin.tag.div +import net.kigawa.renlin.tag.fragment import net.kigawa.renlin.tag.p class Sub { + val state: MutableState = HakateInitializer().newStateDispatcher().newState("state") + val display = div.component { + t("display") + key = "uuid aaaaaaaaa" div { + val value = state.useValue() + key = "key display1 div" + t("display1", key = "key display1") div { + t("display1-1", key = "key display1-1") + key = "key display1-1 div" p { - + t("display1-1-1 $value", key = "key display1-1-1") + key = "key display1-1-1 p" } } } + div { + t("display2") + key = "uuid aawaaaaaaaad" + div { + t("display2-1") + key = "uuid aadaaaaaaa" + } + } + div { + t("display3") + key = "uuid aawaaaaaaaa" + } } val controller = div.component { + t("controller") + key = "uuid aaadaadadsaaaa" } + val test = fragment().component { } + val test1 = fragment().component { } + val test2 = fragment().component { } } \ No newline at end of file diff --git a/sample/src/jsMain/kotlin/net/kigawa/renlin/sample/Main.kt b/sample/src/jsMain/kotlin/net/kigawa/renlin/sample/Main.kt index 8ff02c8..217e30d 100644 --- a/sample/src/jsMain/kotlin/net/kigawa/renlin/sample/Main.kt +++ b/sample/src/jsMain/kotlin/net/kigawa/renlin/sample/Main.kt @@ -1,12 +1,24 @@ package net.kigawa.renlin.sample import kotlinx.browser.document +import kotlinx.browser.window +import net.kigawa.hakate.api.HakateInitializer import net.kigawa.renlin.Entrypoint -import org.w3c.dom.HTMLElement fun main() { val root = document.getElementById("root") ?: throw Exception("Root not found") - if (root !is HTMLElement) throw Exception("Root not html element") - val sample = SampleComponent("sample", Sub()) - Entrypoint(root).render(sample.root) + val sub = Sub() + val sample = SampleComponent("sample", sub) + val dispatcher = HakateInitializer().newStateDispatcher() + Entrypoint(root).render(sample.root, dispatcher) + var i = 0 + window.setInterval( + { + i++ + sample.update(i) + sub.state.set("state $i") + }, + 1000, 10000 + ) + } \ No newline at end of file