Skip to content

Commit 7b5b99b

Browse files
committed
Merge branch 'material-list-prototype'
The visual effects differ greatly on desktop and web with the current implementation.
2 parents b863a68 + e65d9b2 commit 7b5b99b

File tree

8 files changed

+219
-1
lines changed

8 files changed

+219
-1
lines changed

compose-multiplatform-common/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ kotlin {
77
named("commonMain") {
88
dependencies {
99
implementation(compose.runtime)
10+
//compileOnly(compose.foundation) // for KDoc element links only
1011
}
1112
}
1213
named("jvmMain") {

compose-multiplatform-common/src/commonMain/kotlin/com/huanshankeji/compose/ui/ModifierOrAttrsScope.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.huanshankeji.compose.ui
22

3+
//import androidx.compose.ui.Modifier
34
import com.huanshankeji.compose.ui.unit.SizeValue
45

56
typealias ModifierOrAttrs<TElement> = (ModifierOrAttrsScope<TElement>.() -> Unit)?
@@ -14,7 +15,7 @@ expect class StyleScope {
1415
}
1516

1617
/*
17-
/** An alternative immutable design like `Modifier`. */
18+
/** An alternative immutable design like [Modifier]. */
1819
expect class ModifierOrAttrsImmutable<T : Element> {
1920
fun padding(): ModifierOrAttrsImmutable<T>
2021
}

compose-multiplatform-material/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ kotlin {
88
dependencies {
99
implementation(compose.runtime)
1010
api(project(":compose-multiplatform-common"))
11+
//compileOnly(compose.material) // for KDoc element links only
1112
}
1213
}
1314
// TODO: a `jvmCommon` source set to share code for `jvm`/`desktop` and `android`
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package com.huanshankeji.compose.material
2+
3+
//import androidx.compose.foundation.lazy.LazyListScope
4+
import androidx.compose.runtime.Composable
5+
import com.huanshankeji.compose.ui.Element
6+
import com.huanshankeji.compose.ui.ModifierOrAttrs
7+
8+
expect abstract class ListElement : Element
9+
10+
11+
/** @see LazyListScope */
12+
expect class ListScope {
13+
/*
14+
There is a compiler bug of calling the functions below with default arguments.
15+
TODO: report this and put the issue link here
16+
*/
17+
18+
internal fun itemInternal(key: Any? = null, contentType: Any? = null, content: @Composable ItemScope.() -> Unit)
19+
20+
internal fun itemsInternal(
21+
count: Int,
22+
key: ((index: Int) -> Any)? = null,
23+
contentType: (index: Int) -> Any? = { null },
24+
itemContent: @Composable ItemScope.(index: Int) -> Unit
25+
)
26+
27+
internal fun groupInternal(
28+
key: Any? = null,
29+
contentType: Any? = null,
30+
headerContent: @Composable HeaderScope.() -> Unit,
31+
content: ListScope.() -> Unit
32+
)
33+
}
34+
35+
36+
fun ListScope.item(key: Any? = null, contentType: Any? = null, content: @Composable ItemScope.() -> Unit) =
37+
itemInternal(key, contentType, content)
38+
39+
fun ListScope.items(
40+
count: Int,
41+
key: ((index: Int) -> Any)? = null,
42+
contentType: (index: Int) -> Any? = { null },
43+
itemContent: @Composable ItemScope.(index: Int) -> Unit
44+
) =
45+
itemsInternal(count, key, contentType, itemContent)
46+
47+
fun ListScope.group(
48+
key: Any? = null,
49+
contentType: Any? = null,
50+
headerContent: @Composable HeaderScope.() -> Unit,
51+
content: ListScope.() -> Unit
52+
) =
53+
groupInternal(key, contentType, headerContent, content)
54+
55+
56+
expect class ItemScope
57+
expect class HeaderScope
58+
59+
60+
@Composable
61+
expect fun List(modifierOrAttrs: ModifierOrAttrs<ListElement> = null, content: ListScope.() -> Unit)
62+
63+
/**
64+
* An alias for [List] that follows the name of [androidx.compose.foundation.lazy.LazyColumn].
65+
* The current implementation is not actually lazy on web.
66+
*/
67+
@Composable
68+
fun LazyColumn(modifierOrAttrs: ModifierOrAttrs<ListElement> = null, content: ListScope.() -> Unit) =
69+
List(modifierOrAttrs, content)
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package com.huanshankeji.compose.material
2+
3+
import androidx.compose.runtime.Composable
4+
import com.huanshankeji.compose.ui.ModifierOrAttrs
5+
import com.huanshankeji.compose.ui.toAttrs
6+
import dev.petuska.kmdc.list.MDCList
7+
import dev.petuska.kmdc.list.MDCListGroup
8+
import dev.petuska.kmdc.list.MDCListScope
9+
import dev.petuska.kmdc.list.Subheader
10+
import dev.petuska.kmdc.list.item.ListItem
11+
import dev.petuska.kmdc.list.item.MDCListItemScope
12+
import org.jetbrains.compose.web.dom.ElementScope
13+
import org.w3c.dom.HTMLHeadingElement
14+
import org.w3c.dom.HTMLLIElement
15+
import org.w3c.dom.HTMLUListElement
16+
17+
actual typealias ListElement = HTMLUListElement
18+
19+
/**
20+
* This class contains mutable fields.
21+
* @see androidx.compose.foundation.lazy.LazyListScopeImpl
22+
*/
23+
actual class ListScope(
24+
val mdcListScope: MDCListScope<HTMLUListElement>
25+
) {
26+
private var composables: MutableList<@Composable () -> Unit>? = null
27+
private fun addComposable(composable: @Composable () -> Unit) {
28+
composables!!.add(composable)
29+
}
30+
31+
/** Add the composable functions with the non-composable functions and then invoke them. */
32+
@Composable
33+
fun ComposableRun(content: ListScope.() -> Unit) {
34+
composables = mutableListOf()
35+
content()
36+
for (composable in composables!!)
37+
composable()
38+
composables = null
39+
}
40+
41+
42+
actual fun itemInternal(key: Any?, contentType: Any?, content: @Composable ItemScope.() -> Unit) = addComposable {
43+
mdcListScope.ListItem { ItemScope(this).content() }
44+
}
45+
46+
actual fun itemsInternal(
47+
count: Int,
48+
key: ((index: Int) -> Any)?,
49+
contentType: (index: Int) -> Any?,
50+
itemContent: @Composable ItemScope.(index: Int) -> Unit
51+
) = addComposable {
52+
repeat(count) { i ->
53+
mdcListScope.ListItem { ItemScope(this).itemContent(i) }
54+
}
55+
}
56+
57+
actual fun groupInternal(
58+
key: Any?,
59+
contentType: Any?,
60+
headerContent: @Composable HeaderScope.() -> Unit,
61+
content: ListScope.() -> Unit
62+
) = addComposable {
63+
MDCListGroup {
64+
Subheader {
65+
HeaderScope(this).headerContent()
66+
}
67+
MDCList {
68+
ListScope(this).ComposableRun(content)
69+
}
70+
}
71+
}
72+
}
73+
74+
actual class ItemScope(val mdcListItemScope: MDCListItemScope<HTMLLIElement>)
75+
actual class HeaderScope(val elementScope: ElementScope<HTMLHeadingElement>)
76+
77+
@Composable
78+
actual fun List(modifierOrAttrs: ModifierOrAttrs<ListElement>, content: ListScope.() -> Unit) =
79+
MDCList(attrs = modifierOrAttrs.toAttrs()) {
80+
ListScope(this).ComposableRun(content)
81+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package com.huanshankeji.compose.material
2+
3+
import androidx.compose.foundation.ExperimentalFoundationApi
4+
import androidx.compose.foundation.lazy.LazyItemScope
5+
import androidx.compose.foundation.lazy.LazyListScope
6+
import androidx.compose.runtime.Composable
7+
import com.huanshankeji.compose.ui.Element
8+
import com.huanshankeji.compose.ui.ModifierOrAttrs
9+
import com.huanshankeji.compose.ui.toModifier
10+
11+
actual abstract class ListElement : Element()
12+
13+
actual class ListScope(val lazyListScope: LazyListScope) {
14+
actual fun itemInternal(key: Any?, contentType: Any?, content: @Composable ItemScope.() -> Unit) =
15+
lazyListScope.item(key, contentType) { ItemScope(this).content() }
16+
17+
actual fun itemsInternal(
18+
count: Int,
19+
key: ((index: Int) -> Any)?,
20+
contentType: (index: Int) -> Any?,
21+
itemContent: @Composable ItemScope.(index: Int) -> Unit
22+
) =
23+
lazyListScope.items(count, key, contentType) { ItemScope(this).itemContent(it) }
24+
25+
@OptIn(ExperimentalFoundationApi::class)
26+
actual fun groupInternal(
27+
key: Any?,
28+
contentType: Any?,
29+
headerContent: @Composable HeaderScope.() -> Unit,
30+
content: ListScope.() -> Unit
31+
) {
32+
lazyListScope.stickyHeader(key, contentType) { HeaderScope(this).headerContent() }
33+
content()
34+
}
35+
}
36+
37+
actual class ItemScope(val lazyItemScope: LazyItemScope)
38+
actual typealias HeaderScope = ItemScope
39+
40+
@Composable
41+
actual fun List(modifierOrAttrs: ModifierOrAttrs<ListElement>, content: ListScope.() -> Unit) =
42+
androidx.compose.foundation.lazy.LazyColumn(modifierOrAttrs.toModifier()) {
43+
ListScope(this).content()
44+
}

demo/src/commonMain/kotlin/com/huanshankeji/compose/material/demo/Composables.kt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,25 @@ fun App() {
3232
}
3333

3434
IconButton(onClick, materialIcon = MaterialIcons.Search)
35+
36+
List {
37+
item {
38+
Text("Ungrouped item")
39+
}
40+
items(count) {
41+
Text("Ungrouped item $it/$count")
42+
}
43+
group(headerContent = {
44+
Text("Group title")
45+
}) {
46+
item {
47+
Text("Grouped item")
48+
}
49+
items(count) {
50+
Text("Grouped item $it/$count")
51+
}
52+
}
53+
}
3554
}
3655
}
3756
}

gradle.properties

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# for KDoc element links only
2+
#org.jetbrains.compose.experimental.jscanvas.enabled=true

0 commit comments

Comments
 (0)