Skip to content

Commit b0729bd

Browse files
authored
Merge pull request #215 from Qawaz/web
web module working and added
2 parents c6e641d + 4aa4f4d commit b0729bd

10 files changed

Lines changed: 2988 additions & 0 deletions

File tree

gradle.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@ kotlin.code.style=official
1515
org.gradle.jvmargs=-Xmx2048M -Dkotlin.daemon.jvm.options\="-Xmx2048M"
1616
android.useAndroidX=true
1717

18+
org.jetbrains.compose.experimental.jscanvas.enabled=true

kotlin-js-store/yarn.lock

Lines changed: 2738 additions & 0 deletions
Large diffs are not rendered by default.

reorderable/build.gradle.kts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ version = "0.9.7"
1212

1313
kotlin {
1414
jvm()
15+
js(IR) {
16+
browser()
17+
binaries.executable()
18+
}
1519
sourceSets {
1620
val commonMain by getting {
1721
dependencies {

settings.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ rootProject.name = "ComposeReorderList"
1313
include(":android")
1414
include(":desktop")
1515
include(":reorderable")
16+
include(":web")
1617

web/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/build

web/build.gradle.kts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import org.jetbrains.compose.compose
2+
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
3+
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
4+
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension
5+
6+
plugins {
7+
kotlin("multiplatform")
8+
id("org.jetbrains.compose")
9+
}
10+
11+
repositories {
12+
google()
13+
mavenCentral()
14+
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
15+
}
16+
17+
kotlin {
18+
js(IR) {
19+
browser {
20+
testTask {
21+
testLogging.showStandardStreams = true
22+
useKarma {
23+
useChromeHeadless()
24+
useFirefox()
25+
}
26+
}
27+
}
28+
binaries.executable()
29+
}
30+
sourceSets {
31+
val jsMain by getting {
32+
dependencies {
33+
implementation(compose.web.core)
34+
implementation(compose.runtime)
35+
implementation(compose.material)
36+
implementation(project(":reorderable"))
37+
}
38+
}
39+
val jsTest by getting {
40+
dependencies {
41+
implementation(kotlin("test-js"))
42+
}
43+
}
44+
}
45+
}
46+
47+
compose.experimental {
48+
web.application {}
49+
}
50+
51+
afterEvaluate {
52+
rootProject.extensions.configure<NodeJsRootExtension> {
53+
// versions.webpackDevServer.version = "4.0.0"
54+
// versions.webpackCli.version = "4.9.0"
55+
// nodeVersion = "16.0.0"
56+
}
57+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// From Slack by OliverO
2+
// See: https://kotlinlang.slack.com/archives/C01F2HV7868/p1660083429206369?thread_ts=1660083398.571449&cid=C01F2HV7868
3+
4+
@file:Suppress(
5+
"INVISIBLE_MEMBER",
6+
"INVISIBLE_REFERENCE",
7+
"EXPOSED_PARAMETER_TYPE"
8+
) // WORKAROUND: ComposeWindow and ComposeLayer are internal
9+
10+
import androidx.compose.runtime.Composable
11+
import androidx.compose.ui.window.ComposeWindow
12+
import kotlinx.browser.document
13+
import kotlinx.browser.window
14+
import org.w3c.dom.HTMLCanvasElement
15+
import org.w3c.dom.HTMLStyleElement
16+
import org.w3c.dom.HTMLTitleElement
17+
18+
private const val CANVAS_ELEMENT_ID = "ComposeTarget" // Hardwired into ComposeWindow
19+
20+
/**
21+
* A Skiko/Canvas-based top-level window using the browser's entire viewport. Supports resizing.
22+
*/
23+
fun BrowserViewportWindow(
24+
title: String = "Untitled",
25+
content: @Composable ComposeWindow.() -> Unit
26+
) {
27+
val htmlHeadElement = document.head!!
28+
htmlHeadElement.appendChild(
29+
(document.createElement("style") as HTMLStyleElement).apply {
30+
type = "text/css"
31+
appendChild(
32+
document.createTextNode(
33+
"""
34+
html, body {
35+
overflow: hidden;
36+
margin: 0 !important;
37+
padding: 0 !important;
38+
}
39+
#$CANVAS_ELEMENT_ID {
40+
outline: none;
41+
}
42+
""".trimIndent()
43+
)
44+
)
45+
}
46+
)
47+
48+
fun HTMLCanvasElement.fillViewportSize() {
49+
setAttribute("width", "${window.innerWidth}")
50+
setAttribute("height", "${window.innerHeight}")
51+
}
52+
53+
val canvas = (document.getElementById(CANVAS_ELEMENT_ID) as HTMLCanvasElement).apply {
54+
fillViewportSize()
55+
}
56+
57+
ComposeWindow().apply {
58+
window.addEventListener("resize", {
59+
canvas.fillViewportSize()
60+
layer.layer.attachTo(canvas)
61+
val scale = layer.layer.contentScale
62+
layer.setSize((canvas.width / scale).toInt(), (canvas.height / scale).toInt())
63+
layer.layer.needRedraw()
64+
})
65+
66+
// WORKAROUND: ComposeWindow does not implement `setTitle(title)`
67+
val htmlTitleElement = (
68+
htmlHeadElement.getElementsByTagName("title").item(0)
69+
?: document.createElement("title").also { htmlHeadElement.appendChild(it) }
70+
) as HTMLTitleElement
71+
htmlTitleElement.textContent = title
72+
73+
setContent {
74+
content(this)
75+
}
76+
}
77+
}

web/src/jsMain/kotlin/main.js.kt

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import androidx.compose.animation.core.animateDpAsState
2+
import androidx.compose.foundation.Image
3+
import androidx.compose.foundation.VerticalScrollbar
4+
import androidx.compose.foundation.background
5+
import androidx.compose.foundation.layout.*
6+
import androidx.compose.foundation.lazy.LazyColumn
7+
import androidx.compose.foundation.lazy.items
8+
import androidx.compose.foundation.rememberScrollbarAdapter
9+
import androidx.compose.material.Divider
10+
import androidx.compose.material.MaterialTheme
11+
import androidx.compose.material.Text
12+
import androidx.compose.material.icons.Icons
13+
import androidx.compose.material.icons.filled.Menu
14+
import androidx.compose.runtime.Composable
15+
import androidx.compose.runtime.mutableStateOf
16+
import androidx.compose.runtime.remember
17+
import androidx.compose.ui.Alignment
18+
import androidx.compose.ui.Modifier
19+
import androidx.compose.ui.draw.shadow
20+
import androidx.compose.ui.unit.dp
21+
import org.burnoutcrew.reorderable.ReorderableItem
22+
import org.burnoutcrew.reorderable.detectReorder
23+
import org.burnoutcrew.reorderable.rememberReorderableLazyListState
24+
import org.burnoutcrew.reorderable.reorderable
25+
import org.jetbrains.skiko.wasm.onWasmReady
26+
27+
fun main() {
28+
onWasmReady {
29+
BrowserViewportWindow("ComposeReorderableDemo") {
30+
MaterialTheme {
31+
Box(modifier = Modifier.fillMaxSize()) {
32+
VerticalReorderList()
33+
}
34+
}
35+
}
36+
}
37+
}
38+
39+
40+
@Composable
41+
fun VerticalReorderList() {
42+
val items = remember { mutableStateOf(List(100) { it }) }
43+
val state = rememberReorderableLazyListState(onMove = { from, to ->
44+
items.value = items.value.toMutableList().apply {
45+
add(to.index, removeAt(from.index))
46+
}
47+
})
48+
Box {
49+
LazyColumn(
50+
state = state.listState,
51+
modifier = Modifier.reorderable(state)
52+
) {
53+
items(items.value, { it }) { item ->
54+
ReorderableItem(state, orientationLocked = false, key = item) { isDragging ->
55+
val elevation = animateDpAsState(if (isDragging) 8.dp else 0.dp)
56+
Column(
57+
modifier = Modifier
58+
.shadow(elevation.value)
59+
.background(MaterialTheme.colors.surface)
60+
) {
61+
Row(
62+
verticalAlignment = Alignment.CenterVertically,
63+
modifier = Modifier.padding(16.dp)
64+
) {
65+
Image(
66+
imageVector = Icons.Filled.Menu,
67+
contentDescription = "",
68+
modifier = Modifier.detectReorder(state)
69+
)
70+
Text(
71+
text = item.toString(),
72+
modifier = Modifier.padding(start = 8.dp)
73+
)
74+
}
75+
Divider()
76+
}
77+
}
78+
}
79+
}
80+
VerticalScrollbar(
81+
modifier = Modifier.align(Alignment.CenterEnd)
82+
.fillMaxHeight(),
83+
adapter = rememberScrollbarAdapter(state.listState)
84+
)
85+
}
86+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>ComposeReorderableDemo</title>
6+
<script src="skiko.js"></script>
7+
<link type="text/css" rel="stylesheet" href="styles.css"/>
8+
</head>
9+
<body>
10+
<div>
11+
<canvas id="ComposeTarget" width="600" height="600"></canvas>
12+
</div>
13+
<script src="web.js"></script>
14+
</body>
15+
</html>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#root {
2+
width: 100%;
3+
height: 100vh;
4+
}
5+
6+
#root > .compose-web-column > div {
7+
position: relative;
8+
}

0 commit comments

Comments
 (0)