aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client-runtime.ffi.mjs32
-rw-r--r--src/lustre/internals/runtime.gleam18
2 files changed, 48 insertions, 2 deletions
diff --git a/src/client-runtime.ffi.mjs b/src/client-runtime.ffi.mjs
index 51c2eef..ecca48f 100644
--- a/src/client-runtime.ffi.mjs
+++ b/src/client-runtime.ffi.mjs
@@ -1,5 +1,10 @@
import { ElementNotFound, NotABrowser } from "./lustre.mjs";
-import { Dispatch, Shutdown } from "./lustre/internals/runtime.mjs";
+import {
+ Dispatch,
+ Shutdown,
+ Debug,
+ ForceModel,
+} from "./lustre/internals/runtime.mjs";
import { morph } from "./vdom.ffi.mjs";
import { Ok, Error, isEqual } from "./gleam.mjs";
@@ -58,6 +63,11 @@ export class LustreClientApplication {
return;
}
+ case action instanceof Debug: {
+ this.#debug(action[0]);
+ return;
+ }
+
default:
return;
}
@@ -114,6 +124,26 @@ export class LustreClientApplication {
}
}
+ #debug(action) {
+ switch (true) {
+ case action instanceof ForceModel: {
+ const vdom = this.#view(this.#model);
+ const dispatch = (handler) => (e) => {
+ const result = handler(e);
+
+ if (result instanceof Ok) {
+ this.send(new Dispatch(result[0]));
+ }
+ };
+
+ this.#queue = [];
+ this.#effects = [];
+ this.#didUpdate = false;
+ this.#root = morph(this.#root, vdom, dispatch, this.#isComponent);
+ }
+ }
+ }
+
#shutdown() {
this.#root.remove();
this.#root = null;
diff --git a/src/lustre/internals/runtime.gleam b/src/lustre/internals/runtime.gleam
index a2b5365..b2374b4 100644
--- a/src/lustre/internals/runtime.gleam
+++ b/src/lustre/internals/runtime.gleam
@@ -3,8 +3,8 @@
import gleam/dict.{type Dict}
import gleam/dynamic.{type Decoder, type Dynamic}
import gleam/erlang/process.{type Selector, type Subject}
-import gleam/list
import gleam/json.{type Json}
+import gleam/list
import gleam/option.{Some}
import gleam/otp/actor.{type Next, type StartError, Spec}
import gleam/result
@@ -46,6 +46,7 @@ pub type Action(msg, runtime) {
}
pub type DebugAction {
+ ForceModel(Dynamic)
Model(reply: fn(Dynamic) -> Nil)
View(reply: fn(Element(Dynamic)) -> Nil)
}
@@ -133,6 +134,21 @@ fn loop(
loop(Batch(rest, effect.batch([effects, other_effects])), next)
}
+ Debug(ForceModel(model)) -> {
+ let model = dynamic.unsafe_coerce(model)
+ let html = state.view(model)
+ let diff = patch.elements(state.html, html)
+ let next =
+ State(..state, model: model, html: html, handlers: diff.handlers)
+
+ case patch.is_empty_element_diff(diff) {
+ True -> Nil
+ False -> run_renderers(state.renderers, Diff(diff))
+ }
+
+ actor.continue(next)
+ }
+
Debug(Model(reply)) -> {
reply(dynamic.from(state.model))
actor.continue(state)