Type-safe MoonBit bindings for React with virtual DOM, hooks, and CSS-in-JS support (early experimental)
Dependencies
React bindings for MoonBit
import * as React from "react";
import * as ReactDOMClient from "react-dom/client";
window.React = React;
window.ReactDOMClient = ReactDOMClient;// Define your component props
struct ContainerProps {} derive(Default)
// Implement JsValueTrait for props
impl @react.JsValueTrait for ContainerProps with to_value(_self) -> @dom.JsObscure {
@react.JsObject::new().to_value()
}
impl @react.JsValueTrait for ContainerProps with from_value(
_value : @dom.JsObscure,
) -> ContainerProps {
ContainerProps::default()
}
// Create a functional component
fn comp_container(_v : ContainerProps) -> @react.VirtualNode {
let (counter, set_counter) = @react.use_state(0.0.to_float())
@react.div(
id="container",
style=@css.respo_style(
color=Blue,
font_family="Arial",
padding=10.0 |> Px
),
on_click=fn(_) {
println("clicked \{counter}")
set_counter(counter + 1.0)
},
[
@react.Fragment([@react.Text("Demo: ")]),
@react.Text("Counter \{counter}")
],
)
}
// Render to DOM
fn main {
let window = @dom.window()
let doc = window.document()
let body = doc.body()
let props = ContainerProps::default()
@react.render(
@react.component(comp_container, props, []),
body,
)
println("loaded")
}pub type DOMEventpub(all) enum DOMEventType {
Click
DoubleClick
MouseDown
MouseUp
MouseMove
MouseEnter
MouseLeave
MouseOver
MouseOut
ContextMenu
KeyDown
KeyUp
KeyPress
Input
Change
Submit
Reset
Focus
Blur
Select
Load
Unload
Resize
Scroll
Drag
DragStart
DragEnd
DragEnter
DragLeave
DragOver
Drop
TouchStart
TouchMove
TouchEnd
TouchCancel
Error
Abort
CanPlay
CanPlayThrough
DurationChange
Ended
LoadedData
LoadedMetadata
LoadStart
Pause
Play
Playing
Progress
RateChange
Seeked
Seeking
Stalled
Suspend
TimeUpdate
VolumeChange
Waiting
}impl Compare for DOMEventTypeimpl Eq for DOMEventTypeimpl Hash for DOMEventTypeimpl Show for DOMEventTypeimpl Default for ElementAttrs#deprecated("Use `struct T(A)` to declare a newtype and use `.0` access the underlying type instead.")
fn ElementAttrs::inner(self : ElementAttrs) -> Map[String, String]type ElementEventsimpl Default for ElementEventsfn ElementEvents::add(self : ElementEvents, event_type : DOMEventType, value : (DOMEvent) -> Unit) -> ElementEventsfn ElementEvents::set(self : ElementEvents, event_type : DOMEventType, value : (DOMEvent) -> Unit) -> Unitpub(all) enum InputType {
Button
Checkbox
Color
Date
DatetimeLocal
Email
File
Hidden
Image
Month
Number
Password
Radio
Range
Reset
Search
Submit
Tel
Text
Time
Url
Week
}type ReactRef[T]pub struct VirtualElement {
name : String
attrs : ElementAttrs
event : ElementEvents
style : RespoStyle
children : Array[VirtualNode]
}pub(all) enum VirtualNode {
Element(VirtualElement)
Fragment(Array[VirtualNode])
Text(String)
JsNode(JsObscure)
}fn a(id? : String, class_name? : String, class_list? : Array[String], attrs? : ElementAttrs, event? : ElementEvents, style? : RespoStyle, children : Array[VirtualNode], innerHTML? : String, href? : String, target? : String, on_click? : (DOMEvent) -> Unit) -> VirtualNodefn article(id? : String, class_name? : String, class_list? : Array[String], attrs? : ElementAttrs, event? : ElementEvents, style? : RespoStyle, children : Array[VirtualNode], innerHTML? : String, on_click? : (DOMEvent) -> Unit) -> VirtualNodefn aside(id? : String, class_name? : String, class_list? : Array[String], attrs? : ElementAttrs, event? : ElementEvents, style? : RespoStyle, children : Array[VirtualNode], innerHTML? : String, on_click? : (DOMEvent) -> Unit) -> VirtualNodefn audio(id? : String, class_name? : String, class_list? : Array[String], attrs? : ElementAttrs, event? : ElementEvents, style? : RespoStyle, children : Array[VirtualNode], src? : String, controls? : Bool, autoplay? : Bool, loop_enabled? : Bool, muted? : Bool, on_play? : (DOMEvent) -> Unit, on_pause? : (DOMEvent) -> Unit) -> VirtualNodefn button(id? : String, class_name? : String, class_list? : Array[String], attrs? : ElementAttrs, event? : ElementEvents, style? : RespoStyle, children : Array[VirtualNode], innerHTML? : String, button_type? : String, disabled? : Bool, on_click? : (DOMEvent) -> Unit) -> VirtualNodestruct ButtonProps {
text : String
disabled : Bool
} derive(Default)
fn my_button(props : ButtonProps) -> VirtualNode {
button(disabled=props.disabled, [Text(props.text)])
}
let node = component(my_button, ButtonProps { text: "Click me", disabled: false }, [])#callsite(autofill(loc))
fn[U : Show] contained_static_style(rules : Array[(String?, U, RespoStyle)], loc~ : SourceLoc) -> Stringlet style_demo : String = contained_static_style(
[(Some("@media only screen and (max-width: 600px)"), "&", respo_style(margin=4 |> Px, background_color=Hsl(200, 90, 96)))],
)fn create_element(name : String, attrs : ElementAttrs, event : ElementEvents, style~ : RespoStyle, children : Array[VirtualNode]) -> VirtualElement// Create a custom element
let _custom_elem = create_element(
"my-custom-element",
ElementAttrs::new(),
ElementEvents::new(),
style=@css.respo_style(),
[Text("Custom content")]
)fn css_prop_to_camel_case(name : String) -> Stringinspect(css_prop_to_camel_case("background-color"), content="backgroundColor")
inspect(css_prop_to_camel_case("border-top-left-radius"), content="borderTopLeftRadius")
inspect(css_prop_to_camel_case("-webkit-line-clamp"), content="WebkitLineClamp")#deprecated("This function is deprecated.")
#callsite(autofill(loc))
fn[U : Show] declare_contained_style(rules : Array[(String?, U, RespoStyle)], loc~ : SourceLoc) -> Stringfn div(id? : String, class_name? : String, class_list? : Array[String], attrs? : ElementAttrs, event? : ElementEvents, style? : RespoStyle, children : Array[VirtualNode], innerHTML? : String, on_click? : (DOMEvent) -> Unit) -> VirtualNodefn dom_attr_to_react_prop(attr_name : String) -> Stringinspect(dom_attr_to_react_prop("class"), content="className")
inspect(dom_attr_to_react_prop("for"), content="htmlFor")
inspect(dom_attr_to_react_prop("id"), content="id")
inspect(dom_attr_to_react_prop("data-test"), content="data-test")inspect(dom_event_to_react_handler(KeyDown), content="onKeyDown")
inspect(dom_event_to_react_handler(Click), content="onClick")
inspect(dom_event_to_react_handler(MouseEnter), content="onMouseEnter")
inspect(dom_event_to_react_handler(DoubleClick), content="onDoubleClick")fn footer(id? : String, class_name? : String, class_list? : Array[String], attrs? : ElementAttrs, event? : ElementEvents, style? : RespoStyle, children : Array[VirtualNode], innerHTML? : String, on_click? : (DOMEvent) -> Unit) -> VirtualNodefn h1(id? : String, class_name? : String, class_list? : Array[String], attrs? : ElementAttrs, event? : ElementEvents, style? : RespoStyle, children : Array[VirtualNode], innerHTML? : String, on_click? : (DOMEvent) -> Unit) -> VirtualNodefn h2(id? : String, class_name? : String, class_list? : Array[String], attrs? : ElementAttrs, event? : ElementEvents, style? : RespoStyle, children : Array[VirtualNode], innerHTML? : String, on_click? : (DOMEvent) -> Unit) -> VirtualNodefn h3(id? : String, class_name? : String, class_list? : Array[String], attrs? : ElementAttrs, event? : ElementEvents, style? : RespoStyle, children : Array[VirtualNode], innerHTML? : String, on_click? : (DOMEvent) -> Unit) -> VirtualNodefn h4(id? : String, class_name? : String, class_list? : Array[String], attrs? : ElementAttrs, event? : ElementEvents, style? : RespoStyle, children : Array[VirtualNode], innerHTML? : String, on_click? : (DOMEvent) -> Unit) -> VirtualNodefn h5(id? : String, class_name? : String, class_list? : Array[String], attrs? : ElementAttrs, event? : ElementEvents, style? : RespoStyle, children : Array[VirtualNode], innerHTML? : String, on_click? : (DOMEvent) -> Unit) -> VirtualNodefn h6(id? : String, class_name? : String, class_list? : Array[String], attrs? : ElementAttrs, event? : ElementEvents, style? : RespoStyle, children : Array[VirtualNode], innerHTML? : String, on_click? : (DOMEvent) -> Unit) -> VirtualNodefn header(id? : String, class_name? : String, class_list? : Array[String], attrs? : ElementAttrs, event? : ElementEvents, style? : RespoStyle, children : Array[VirtualNode], innerHTML? : String, on_click? : (DOMEvent) -> Unit) -> VirtualNodefn img(id? : String, class_name? : String, class_list? : Array[String], attrs? : ElementAttrs, event? : ElementEvents, style? : RespoStyle, src? : String, alt? : String, width? : String, height? : String, on_click? : (DOMEvent) -> Unit, on_load? : (DOMEvent) -> Unit, on_error? : (DOMEvent) -> Unit) -> VirtualNodefn input(id? : String, class_name? : String, class_list? : Array[String], attrs? : ElementAttrs, event? : ElementEvents, style? : RespoStyle, type_? : InputType, value? : String, placeholder? : String, disabled? : Bool, on_click? : (DOMEvent) -> Unit, on_change? : (DOMEvent) -> Unit, on_input? : (DOMEvent) -> Unit) -> VirtualNodefn is_boolean_prop(prop_name : String) -> Boolinspect(is_boolean_prop("checked"), content="true")
inspect(is_boolean_prop("disabled"), content="true")
inspect(is_boolean_prop("readOnly"), content="true")
inspect(is_boolean_prop("className"), content="false")fn label(id? : String, class_name? : String, class_list? : Array[String], attrs? : ElementAttrs, event? : ElementEvents, style? : RespoStyle, children : Array[VirtualNode], innerHTML? : String, on_click? : (DOMEvent) -> Unit, for_? : String) -> VirtualNodefn li(id? : String, class_name? : String, class_list? : Array[String], attrs? : ElementAttrs, event? : ElementEvents, style? : RespoStyle, children : Array[VirtualNode], innerHTML? : String, on_click? : (DOMEvent) -> Unit) -> VirtualNodefn nav(id? : String, class_name? : String, class_list? : Array[String], attrs? : ElementAttrs, event? : ElementEvents, style? : RespoStyle, children : Array[VirtualNode], innerHTML? : String, on_click? : (DOMEvent) -> Unit) -> VirtualNodefn ol(id? : String, class_name? : String, class_list? : Array[String], attrs? : ElementAttrs, event? : ElementEvents, style? : RespoStyle, children : Array[VirtualNode], innerHTML? : String, on_click? : (DOMEvent) -> Unit) -> VirtualNodefn option(id? : String, class_name? : String, class_list? : Array[String], attrs? : ElementAttrs, event? : ElementEvents, style? : RespoStyle, children : Array[VirtualNode], innerHTML? : String, value? : String, selected? : Bool, disabled? : Bool) -> VirtualNodefn p(id? : String, class_name? : String, class_list? : Array[String], attrs? : ElementAttrs, event? : ElementEvents, style? : RespoStyle, children : Array[VirtualNode], innerHTML? : String, on_click? : (DOMEvent) -> Unit) -> VirtualNode// Render a virtual element to the document body
let custom_elem = create_element(
"my-custom-element",
ElementAttrs::new(),
ElementEvents::new(),
style=@css.respo_style(),
[Text("Custom content")]
)
render(custom_elem.to_node(), document.body)fn section(id? : String, class_name? : String, class_list? : Array[String], attrs? : ElementAttrs, event? : ElementEvents, style? : RespoStyle, children : Array[VirtualNode], innerHTML? : String, on_click? : (DOMEvent) -> Unit) -> VirtualNodefn select(id? : String, class_name? : String, class_list? : Array[String], attrs? : ElementAttrs, event? : ElementEvents, style? : RespoStyle, children : Array[VirtualNode], value? : String, disabled? : Bool, multiple? : Bool, on_change? : (DOMEvent) -> Unit) -> VirtualNodefn span(id? : String, class_name? : String, class_list? : Array[String], attrs? : ElementAttrs, event? : ElementEvents, style? : RespoStyle, children : Array[VirtualNode], innerHTML? : String, on_click? : (DOMEvent) -> Unit) -> VirtualNodelet _ = span(
class_name="text-bold",
on_click=fn(_e) { println("Clicked!") }, []
)#callsite(autofill(loc))
fn[U : Show] static_style(rules : Array[(U, RespoStyle)], loc~ : SourceLoc) -> Stringlet style_demo : String = static_style(
[("&", respo_style(margin=4 |> Px, background_color=Hsl(200, 90, 96)))],
)fn textarea(id? : String, class_name? : String, class_list? : Array[String], attrs? : ElementAttrs, event? : ElementEvents, style? : RespoStyle, value? : String, placeholder? : String, rows? : Int, cols? : Int, disabled? : Bool, on_change? : (DOMEvent) -> Unit, on_input? : (DOMEvent) -> Unit) -> VirtualNodefn ul(id? : String, class_name? : String, class_list? : Array[String], attrs? : ElementAttrs, event? : ElementEvents, style? : RespoStyle, children : Array[VirtualNode], innerHTML? : String, on_click? : (DOMEvent) -> Unit) -> VirtualNodefn video(id? : String, class_name? : String, class_list? : Array[String], attrs? : ElementAttrs, event? : ElementEvents, style? : RespoStyle, children : Array[VirtualNode], src? : String, controls? : Bool, autoplay? : Bool, loop_enabled? : Bool, muted? : Bool, width? : String, height? : String, on_click? : (DOMEvent) -> Unit, on_play? : (DOMEvent) -> Unit, on_pause? : (DOMEvent) -> Unit) -> VirtualNodeInstall
Download zipType-safe MoonBit bindings for React with virtual DOM, hooks, and CSS-in-JS support (early experimental)
Dependencies