Current section
Files
Jump to
Current section
Files
src/novdom/state.gleam
import novdom/internals/utils
pub type StateId =
String
// TODO: Make opaque
/// **Attention:** Will be opaque soon.
pub type State(a) {
State(state_id: StateId)
StateList(state_id: StateId)
StateItem(state_id: StateId, root_id: StateId)
}
/// Create a state with an initial value. \
/// If you want to create a state with a list, use `create_list(..)` - it is way more efficient plus you can use all `novdom/state/list` functions.
pub fn create(init: a) -> State(a) {
let id = utils.unique_id()
set_state(id, init)
State(id)
}
/// Create a state with a list as an initial value. \
/// This enables all `novdom/state/list` functions.
pub fn create_list(init: List(a)) -> State(List(a)) {
let id = utils.unique_id()
set_state_list(id, init)
StateList(id)
}
/// Create a state with a specific id. \
/// If a state with the same id already exists, it will be overwritten. \
/// To get a state with a specific id, use `from_id(..)`.
pub fn create_with_id(id: StateId, init: a) -> State(a) {
set_state(id, init)
State(id)
}
/// Create a state with a list as an initial value and a specific id. \
/// For more information, see `create_with_id(..)` and `create_list(..)`.
pub fn create_list_with_id(id: StateId, init: List(a)) -> State(List(a)) {
set_state_list(id, init)
StateList(id)
}
/// Get a state with a specific id. \
/// **Warning:** The state with this id needs to be created before (see `create_with_id(..)`). Otherwise this can lead to unexpected behavior.
pub fn from_id(id: StateId) -> State(a) {
State(id)
}
/// Get a state with a specific id that holds a list value. \
/// For more information, see `from_id(..)`.
pub fn list_from_id(id: StateId) -> State(List(a)) {
StateList(id)
}
// TODO: Remove (should be collected by functions (like utilize / update))
/// Get the current value of a state.
pub fn value(state: State(a)) -> a {
case state {
State(id) -> get_state_value(id)
StateList(id) -> get_state_list_value(id)
StateItem(id, root_id) -> get_state_list_item_value(id, root_id)
}
}
// TODO: chnage to fn (e.g. update(state, fn(old_value) -> new_value) -> new_value)
/// Update / overwrite the value of a state. \
/// If you want to update a `StateList`, see `novdom/state/list`.
pub fn update(state: State(a), new: a) -> Nil {
case state {
State(id) -> set_state(id, new)
StateList(id) -> overwrite_state_list(id, new)
StateItem(id, root_id) -> set_state_list_item(id, root_id, new)
}
}
/// Update / overwrite the value of a state using a function that receives the current value of the state. \
/// If you want to update a `StateList`, see `novdom/state/list`.
pub fn update_fn(state: State(a), do: fn(a) -> a) -> a {
let new =
state
|> value()
|> do()
state
|> update(new)
new
}
/// Listen to a state. \
/// The callback will be called whenever the state changes.
pub fn listen(state: State(a), callback: fn(a) -> Nil) -> Nil {
add_state_listener(state.state_id, callback)
}
@external(javascript, "../document_ffi.mjs", "get_state_value")
fn get_state_value(id: StateId) -> a
@external(javascript, "../document_ffi.mjs", "get_state_list_value")
fn get_state_list_value(id: StateId) -> a
@external(javascript, "../document_ffi.mjs", "get_state_list_item_value")
fn get_state_list_item_value(id: StateId, root_id: StateId) -> a
@external(javascript, "../document_ffi.mjs", "set_state")
fn set_state(id: StateId, value: a) -> Nil
@external(javascript, "../document_ffi.mjs", "set_state_list")
fn set_state_list(id: StateId, value: List(a)) -> Nil
@external(javascript, "../document_ffi.mjs", "overwrite_state_list")
fn overwrite_state_list(id: StateId, value: a) -> Nil
@external(javascript, "../document_ffi.mjs", "set_state_list_item")
fn set_state_list_item(id: StateId, root_id: StateId, value: a) -> Nil
@external(javascript, "../document_ffi.mjs", "add_state_listener")
fn add_state_listener(id: StateId, callback: fn(a) -> Nil) -> Nil