rsignal - A reactive web programming library for Moonbit
///|
fnalias @rsignal.(div, button, style, onclick, h)
///|
typealias @web.(HTMLDivElement, ReactiveElement as RE, ReactiveAttr as RA)
///|
fn counter(initial_count : Int) -> HTMLDivElement {
let state = @reactive_core.new(initial_count) // root signal
div([
style("display: flex; flex-direction: column; align-items: center;"),
h("h2", ["The Greatest Counter Ever!"]),
div([
style("display: flex; flex-direction: row; column-gap: 1em;"),
button("Decrement", [
onclick(_ => state.update(state.val() - 1)),
RA::disabled(state.map(count => count <= 0)), // Disable button when count is 0
]),
RE::text(state, (txt, cur_count) => txt.set_text_content(cur_count)),
button("Increment", [onclick(_ => state.update(state.val() + 1))]),
]),
])
}
///|
fn main {
let el = counter(0)
@reactive_web.mount_to_body(el)
}type Rsignal[T]let filtered_values = []
let s = new(1)
let s2 = s.filter(fn(v) { v > 5 }, 0)
s2.subscribe_permanent_only(fn(v) { filtered_values.push(v) })
s.update(10) // This will trigger the subscriber with value 10.
s.update(7) // This will trigger the subscriber with value 7.
s.update(3) // This will not trigger the subscriber.
inspect(filtered_values, content="[10, 7]")let mapped_values = []
let s = new(1)
let s2 = s.filter_map(fn(v) { if v > 5 { Some(v+2) } else { None } }, 0)
s2.subscribe_permanent_only(fn(v) { mapped_values.push(v) })
s.update(10) // This will trigger the subscriber with value 12.
s.update(7) // This will trigger the subscriber with value 9.
s.update(3) // This will not trigger the subscriber.
inspect(mapped_values, content="[12, 9]")let s = new(0)
assert_eq(s.id(), "signal#0")
let s2 = new(1, label="my_signal")
assert_eq(s2.id(), "my_signal#1")let values = []
let s = new(0)
let s2 = s.map(fn(v) { v + 1 })
s2.subscribe_permanent(fn(v) { values.push(v) })
s.update(5) // This will trigger the subscriber with value 6.
s.update(10) // This will trigger the subscriber with value 11.
s.update(20) // This will trigger the subscriber with value 21.
inspect(values, content="[1, 6, 11, 21]")let values = []
let s = new(0)
let sub = s.subscribe(fn(v) { values.push(v) })
assert_eq(s.val(), 0)
s.update(5) // This will notify subscribers with the new value.
assert_eq(s.val(), 5)
assert_eq(values, [0, 5])
s.unsubscribe(sub) // This will unsubscribe the subscriber.
assert_eq(s.val(), 5)
s.update(10) // This will not notify the unsubscribed subscriber.
assert_eq(s.val(), 10)
assert_eq(values, [0, 5])let values = []
let s = new(0)
s.subscribe_permanent(fn(v) { values.push(v) })
assert_eq(s.val(), 0)
s.update(5) // This will notify subscribers with the new value.
assert_eq(s.val(), 5)
assert_eq(values, [0, 5])
s.update(10) // This will notify subscribers with the new value.
assert_eq(s.val(), 10)
assert_eq(values, [0, 5, 10])let values = []
let s1 = new(1)
let s2 = new(2)
let s3 = new(3)
let s4 = new(4)
let combined_signal = combine_all([s1, s2, s3, s4])
combined_signal.subscribe_permanent(fn(v) { values.push(v) })
s1.update(5) // This will trigger the subscriber with value [5, 2, 3, 4].
s2.update(6) // This will trigger the subscriber with value [5, 6, 3, 4].
s3.update(7) // This will trigger the subscriber with value [5, 6, 7, 4].
s4.update(8) // This will trigger the subscriber with value [5, 6, 7, 8].
inspect(values, content="[[1, 2, 3, 4], [5, 2, 3, 4], [5, 6, 3, 4], [5, 6, 7, 4], [5, 6, 7, 8]]")let values = []
let s1 = new(1)
let s2 = new(2)
let s3 = combine_pair(s1, s2)
s3.subscribe_permanent(fn(v) { values.push(v) })
s1.update(3) // This will trigger the subscriber with value (3, 2).
s2.update(4) // This will trigger the subscriber with value (3, 4).
s1.update(5) // This will trigger the subscriber with value (5, 4).
inspect(values, content="[(1, 2), (3, 2), (3, 4), (5, 4)]")let values = []
let s1 = new(1)
let s2 = new(2)
let s3 = new(3)
let s4 = combine_triple(s1, s2, s3)
s4.subscribe_permanent(fn(v) { values.push(v) })
s1.update(4) // This will trigger the subscriber with value (4, 2, 3).
s2.update(5) // This will trigger the subscriber with value (4, 5, 3).
s3.update(6) // This will trigger the subscriber with value (4, 5, 6).
s1.update(7) // This will trigger the subscriber with value (7, 5, 6).
inspect(values, content="[(1, 2, 3), (4, 2, 3), (4, 5, 3), (4, 5, 6), (7, 5, 6)]")let values = []
let s1 = new(1)
let s2 = new(2)
let s3 = map2(s1, s2, fn(a, b) { a + b })
s3.subscribe_permanent(fn(v) { values.push(v) })
s1.update(3) // This will trigger the subscriber with value 5.
s2.update(4) // This will trigger the subscriber with value 7.
s1.update(5) // This will trigger the subscriber with value 9.
inspect(values, content="[3, 5, 7, 9]")let values = []
let s1 = new(1)
let s2 = new(2)
let s3 = new(3)
let combined_signal = select_one([s1, s2, s3])
combined_signal.subscribe_permanent_only(fn(v) { values.push(v) })
s1.update(4) // This will trigger the subscriber with value 4.
s2.update(5) // This will trigger the subscriber with value 5.
s3.update(6) // This will trigger the subscriber with value 6.
inspect(values, content="[4, 5, 6]")rsignal - A reactive web programming library for Moonbit