You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
385 lines
9.3 KiB
385 lines
9.3 KiB
package org.jetbrains.compose.web.sample |
|
|
|
import androidx.compose.runtime.Composable |
|
import androidx.compose.runtime.MutableState |
|
import androidx.compose.runtime.State |
|
import androidx.compose.runtime.derivedStateOf |
|
import androidx.compose.runtime.getValue |
|
import androidx.compose.runtime.mutableStateOf |
|
import androidx.compose.runtime.remember |
|
import androidx.compose.runtime.setValue |
|
import org.jetbrains.compose.web.renderComposableInBody |
|
import org.jetbrains.compose.web.sample.tests.launchTestCase |
|
import kotlinx.browser.window |
|
import kotlinx.coroutines.MainScope |
|
import kotlinx.coroutines.delay |
|
import kotlinx.coroutines.launch |
|
import org.jetbrains.compose.web.ExperimentalComposeWebStyleApi |
|
import org.jetbrains.compose.web.attributes.* |
|
import org.jetbrains.compose.web.css.* |
|
import org.jetbrains.compose.web.dom.* |
|
import org.w3c.dom.url.URLSearchParams |
|
|
|
class State { |
|
var isDarkTheme by mutableStateOf(false) |
|
} |
|
|
|
val globalState = State() |
|
val globalInt = mutableStateOf(1) |
|
|
|
object MyCSSVariables { |
|
val myVar by variable<CSSColorValue>() |
|
val myVar2 by variable<StylePropertyString>() |
|
} |
|
|
|
object AppStyleSheet : StyleSheet() { |
|
val bounce by keyframes { |
|
from { |
|
property("transform", "translateX(50%)") |
|
} |
|
|
|
to { |
|
property("transform", "translateX(-50%)") |
|
} |
|
} |
|
|
|
val myClass by style { |
|
color(Color.green) |
|
animation(bounce) { |
|
duration(2.s) |
|
timingFunction(AnimationTimingFunction.EaseIn) |
|
direction(AnimationDirection.Alternate) |
|
} |
|
} |
|
|
|
val classWithNested by style { |
|
color(Color.green) |
|
|
|
MyCSSVariables.myVar(Color("blue")) |
|
MyCSSVariables.myVar2("red") |
|
|
|
hover(self) style { |
|
color(Color.red) |
|
} |
|
|
|
border { |
|
width(1.px) |
|
style(LineStyle.Solid) |
|
color(MyCSSVariables.myVar.value()) |
|
} |
|
|
|
media(mediaMaxWidth(640.px)) { |
|
self style { |
|
backgroundColor(MyCSSVariables.myVar.value()) |
|
property("color", MyCSSVariables.myVar2.value()) |
|
} |
|
} |
|
} |
|
} |
|
|
|
object Auto : StyleSheet(AppStyleSheet) |
|
|
|
const val MyClassName = "MyClassName" |
|
|
|
@Composable |
|
fun CounterApp(counter: MutableState<Int>) { |
|
Counter(counter.value) |
|
|
|
Button( |
|
{ |
|
style { |
|
color(if (counter.value % 2 == 0) Color.green else Color.red) |
|
width((counter.value + 200).px) |
|
fontSize(if (counter.value % 2 == 0) 25.px else 30.px) |
|
margin(15.px) |
|
} |
|
|
|
onClick { counter.value = counter.value + 1 } |
|
} |
|
) { |
|
Text("Increment ${counter.value}") |
|
} |
|
} |
|
|
|
@Composable |
|
fun Counter(value: Int) { |
|
Div( |
|
attrs = { |
|
classes("counter") |
|
id("counter") |
|
draggable(Draggable.True) |
|
attr("title", "This is a counter!") |
|
onDrag { println("DRAGGING NOW!!!!") } |
|
|
|
style { |
|
color(Color.red) |
|
} |
|
} |
|
) { |
|
Text("Counter = $value") |
|
} |
|
} |
|
|
|
@OptIn(ExperimentalComposeWebStyleApi::class) |
|
fun main() { |
|
val urlParams = URLSearchParams(window.location.search) |
|
|
|
if (urlParams.has("test")) { |
|
launchTestCase(urlParams.get("test") ?: "") |
|
return |
|
} |
|
|
|
renderComposableInBody { |
|
println("renderComposable") |
|
val counter = remember { mutableStateOf(0) } |
|
|
|
CheckboxInput(checked = false) { |
|
onInput { |
|
println("Checkbox input = ${it.value}") |
|
} |
|
onChange { |
|
println("Checkbox onChange = ${it.value}") |
|
} |
|
} |
|
|
|
var emailState by remember { mutableStateOf("") } |
|
var rangeState by remember { mutableStateOf<Number>(10) } |
|
|
|
TextInput(value = emailState) { |
|
onInput { |
|
println("Typed value = ${it.value}") |
|
emailState = it.value |
|
} |
|
} |
|
|
|
NumberInput(value = 10) { |
|
onBeforeInput { println(("number onBeforeInput = ${it.value}")) } |
|
onInput { println(("number onInput = ${it.value}")) } |
|
onChange { println(("number onChange = ${it.value}")) } |
|
} |
|
|
|
RangeInput(rangeState) { |
|
onBeforeInput { println(("RangeInput onBeforeInput = ${it.value}")) } |
|
onInput { |
|
println(("RangeInput onInput = ${it.value}")) |
|
rangeState = it.value ?: 0 |
|
} |
|
} |
|
|
|
MonthInput(value = "2021-10") { |
|
onInput { |
|
println("Month = ${it.value}") |
|
} |
|
} |
|
|
|
CounterApp(counter) |
|
|
|
val inputValue = remember { mutableStateOf("") } |
|
|
|
smallColoredTextWithState( |
|
text = derivedStateOf { |
|
if (inputValue.value.isNotEmpty()) { |
|
" ___ " + inputValue.value |
|
} else { |
|
"" |
|
} |
|
} |
|
) |
|
|
|
A(href = "http://127.0.0.1") { |
|
Text("Click Me") |
|
} |
|
|
|
MyInputComponent(text = inputValue) { |
|
inputValue.value = it |
|
} |
|
|
|
Text("inputValue.value" + inputValue.value) |
|
|
|
Style { |
|
className(MyClassName) style { |
|
opacity(0.3) |
|
} |
|
|
|
className(MyClassName) + hover() style { |
|
opacity(1) |
|
} |
|
|
|
".${AppStyleSheet.myClass}:hover" { |
|
color(Color.red) |
|
} |
|
|
|
media(mediaMinWidth(500.px) and mediaMaxWidth(700.px)) { |
|
className(MyClassName) style { |
|
fontSize(40.px) |
|
} |
|
} |
|
} |
|
Style(AppStyleSheet) |
|
|
|
Div( |
|
attrs = { |
|
classes( |
|
AppStyleSheet.classWithNested |
|
) |
|
} |
|
) { |
|
Text("My text") |
|
} |
|
|
|
Div( |
|
attrs = { |
|
classes(MyClassName) |
|
} |
|
) { |
|
Text("My text") |
|
} |
|
|
|
Div({ |
|
classes( |
|
AppStyleSheet.myClass |
|
) |
|
|
|
style { |
|
opacity(0.3) |
|
} |
|
}) { |
|
Text("My text") |
|
} |
|
|
|
Div( |
|
attrs = { |
|
classes( |
|
Auto.css { |
|
color(Color.pink) |
|
hover(self) style { |
|
color(Color.blue) |
|
} |
|
} |
|
) |
|
|
|
style { |
|
opacity(30.percent) |
|
} |
|
} |
|
) { |
|
Text("My text") |
|
} |
|
|
|
KotlinCodeSnippets() |
|
} |
|
|
|
MainScope().launch { |
|
while (true) { |
|
delay(3000) |
|
globalState.isDarkTheme = !globalState.isDarkTheme |
|
} |
|
} |
|
} |
|
|
|
@Composable |
|
fun MyInputComponent(text: State<String>, onChange: (String) -> Unit) { |
|
Div({ |
|
style { |
|
padding(50.px) |
|
} |
|
|
|
onTouchStart { |
|
println("On touch start") |
|
} |
|
onTouchEnd { |
|
println("On touch end") |
|
} |
|
}) { |
|
Text("Test onMouseDown") |
|
} |
|
|
|
Div { |
|
TextArea( |
|
value = text.value, |
|
attrs = { |
|
onKeyDown { |
|
println("On keyDown key = : ${it.getNormalizedKey()}") |
|
} |
|
onInput { |
|
onChange(it.value) |
|
} |
|
onKeyUp { |
|
println("On keyUp key = : ${it.getNormalizedKey()}") |
|
} |
|
} |
|
) |
|
} |
|
Div { |
|
Input(type = InputType.Checkbox, attrs = { |
|
onInput { |
|
println("From div - Checked: " + it.value) |
|
} |
|
}) |
|
Input(type = InputType.Text, attrs = { |
|
value(value = "Hi, ") |
|
}) |
|
} |
|
Div { |
|
Input( |
|
type = InputType.Radio, |
|
attrs = { |
|
onInput { |
|
println("Radio 1 - Checked: " + it.value) |
|
} |
|
name("f1") |
|
} |
|
) |
|
Input( |
|
type = InputType.Radio, |
|
attrs = { |
|
onInput { |
|
println("Radio 2 - Checked: " + it.value) |
|
} |
|
name("f1") |
|
} |
|
) |
|
Input(type = InputType.Radio, attrs = {}) |
|
} |
|
} |
|
|
|
@Composable |
|
fun smallColoredTextWithState(text: State<String>) { |
|
smallColoredText(text = text.value) |
|
} |
|
|
|
@Composable |
|
fun smallColoredText(text: String) { |
|
if (globalInt.value < 5) { |
|
Div( |
|
attrs = { |
|
if (globalInt.value > 2) { |
|
id("someId-${globalInt.value}") |
|
} |
|
|
|
classes("someClass") |
|
|
|
attr("customAttr", "customValue") |
|
|
|
onClick { |
|
globalInt.value = globalInt.value + 1 |
|
} |
|
|
|
ref { element -> |
|
println("DIV CREATED ${element.id}") |
|
onDispose { println("DIV REMOVED ${element.id}") } |
|
} |
|
|
|
style { |
|
if (globalState.isDarkTheme) { |
|
color(Color.black) |
|
} else { |
|
color(Color.green) |
|
} |
|
} |
|
}, |
|
) { |
|
Text("Text = $text") |
|
} |
|
} |
|
}
|
|
|