diff --git a/hosts/ocaml/bin/sx_server.ml b/hosts/ocaml/bin/sx_server.ml index 4f3ae90a..66ff6612 100644 --- a/hosts/ocaml/bin/sx_server.ml +++ b/hosts/ocaml/bin/sx_server.ml @@ -657,6 +657,8 @@ let make_server_env () = match v with | Thunk (body, closure_env) -> Sx_ref.eval_expr body (Env closure_env) | other -> other); + (* client? returns false on server — overridden in browser via K.eval *) + ignore (env_bind env "client?" (NativeFn ("client?", fun _ -> Bool false))); env diff --git a/hosts/ocaml/browser/sx_browser.ml b/hosts/ocaml/browser/sx_browser.ml index b5c983a1..faf0d4f8 100644 --- a/hosts/ocaml/browser/sx_browser.ml +++ b/hosts/ocaml/browser/sx_browser.ml @@ -439,6 +439,9 @@ let api_fn_arity fn_js = let () = let bind name fn = ignore (env_bind global_env name (NativeFn (name, fn))) in + (* client? returns true in browser — set the ref so the primitive returns true *) + Sx_primitives._is_client := true; + (* --- Evaluation --- *) bind "cek-eval" (fun args -> match args with diff --git a/hosts/ocaml/lib/sx_primitives.ml b/hosts/ocaml/lib/sx_primitives.ml index d0547f3d..c1c17cb6 100644 --- a/hosts/ocaml/lib/sx_primitives.ml +++ b/hosts/ocaml/lib/sx_primitives.ml @@ -12,6 +12,7 @@ let _sx_call_fn : (value -> value list -> value) ref = ref (fun _ _ -> raise (Eval_error "sx_call not initialized")) let _sx_trampoline_fn : (value -> value) ref = ref (fun v -> v) +let _is_client : bool ref = ref false let register name fn = Hashtbl.replace primitives name fn @@ -664,6 +665,8 @@ let () = match args with [String msg] -> raise (Eval_error msg) | [a] -> raise (Eval_error (to_string a)) | _ -> raise (Eval_error "error: 1 arg")); + (* client? — false by default (server); sx_browser.ml sets _is_client := true *) + register "client?" (fun _args -> Bool !_is_client); register "apply" (fun args -> let call f a = match f with diff --git a/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-021b44b5.wasm b/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-021b44b5.wasm new file mode 100644 index 00000000..544c3c5a Binary files /dev/null and b/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-021b44b5.wasm differ diff --git a/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-2417e073.wasm b/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-2417e073.wasm new file mode 100644 index 00000000..813ae2cd Binary files /dev/null and b/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-2417e073.wasm differ diff --git a/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-281c8ec9.wasm b/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-281c8ec9.wasm new file mode 100644 index 00000000..9e1b65c3 Binary files /dev/null and b/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-281c8ec9.wasm differ diff --git a/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-2e951671.wasm b/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-2e951671.wasm new file mode 100644 index 00000000..53d37371 Binary files /dev/null and b/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-2e951671.wasm differ diff --git a/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-3e22a7b3.wasm b/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-3e22a7b3.wasm new file mode 100644 index 00000000..f2d6da0d Binary files /dev/null and b/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-3e22a7b3.wasm differ diff --git a/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-3f86f26c.wasm b/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-3f86f26c.wasm new file mode 100644 index 00000000..ada56092 Binary files /dev/null and b/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-3f86f26c.wasm differ diff --git a/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-6b156118.wasm b/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-6b156118.wasm new file mode 100644 index 00000000..c596c250 Binary files /dev/null and b/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-6b156118.wasm differ diff --git a/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-7009ef0a.wasm b/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-7009ef0a.wasm new file mode 100644 index 00000000..3f3d3529 Binary files /dev/null and b/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-7009ef0a.wasm differ diff --git a/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-7875a983.wasm b/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-7875a983.wasm new file mode 100644 index 00000000..84d7eb73 Binary files /dev/null and b/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-7875a983.wasm differ diff --git a/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-88a6485c.wasm b/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-88a6485c.wasm new file mode 100644 index 00000000..464f74be Binary files /dev/null and b/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-88a6485c.wasm differ diff --git a/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-a885ccbf.wasm b/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-a885ccbf.wasm new file mode 100644 index 00000000..7391e054 Binary files /dev/null and b/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-a885ccbf.wasm differ diff --git a/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-b706e6fb.wasm b/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-b706e6fb.wasm new file mode 100644 index 00000000..084eb76b Binary files /dev/null and b/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-b706e6fb.wasm differ diff --git a/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-b9f0c136.wasm b/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-b9f0c136.wasm new file mode 100644 index 00000000..70974735 Binary files /dev/null and b/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-b9f0c136.wasm differ diff --git a/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-c7255f12.wasm b/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-c7255f12.wasm new file mode 100644 index 00000000..9be2fe1e Binary files /dev/null and b/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-c7255f12.wasm differ diff --git a/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-c7eb9ed0.wasm b/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-c7eb9ed0.wasm new file mode 100644 index 00000000..14e62de5 Binary files /dev/null and b/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-c7eb9ed0.wasm differ diff --git a/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-db2900ae.wasm b/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-db2900ae.wasm new file mode 100644 index 00000000..db15bb73 Binary files /dev/null and b/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-db2900ae.wasm differ diff --git a/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-ed26e042.wasm b/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-ed26e042.wasm new file mode 100644 index 00000000..2c035c61 Binary files /dev/null and b/shared/static/wasm/sx_browser.bc.wasm.assets/dune__exe__Sx_browser-ed26e042.wasm differ diff --git a/shared/static/wasm/sx_browser.bc.wasm.assets/sx-2ec218f4.wasm b/shared/static/wasm/sx_browser.bc.wasm.assets/sx-2ec218f4.wasm new file mode 100644 index 00000000..0caabd29 Binary files /dev/null and b/shared/static/wasm/sx_browser.bc.wasm.assets/sx-2ec218f4.wasm differ diff --git a/shared/static/wasm/sx_browser.bc.wasm.assets/sx-31fbd690.wasm b/shared/static/wasm/sx_browser.bc.wasm.assets/sx-31fbd690.wasm new file mode 100644 index 00000000..ebd8c820 Binary files /dev/null and b/shared/static/wasm/sx_browser.bc.wasm.assets/sx-31fbd690.wasm differ diff --git a/shared/static/wasm/sx_browser.bc.wasm.assets/sx-3909a451.wasm b/shared/static/wasm/sx_browser.bc.wasm.assets/sx-3909a451.wasm new file mode 100644 index 00000000..73d8c284 Binary files /dev/null and b/shared/static/wasm/sx_browser.bc.wasm.assets/sx-3909a451.wasm differ diff --git a/shared/static/wasm/sx_browser.bc.wasm.assets/sx-3b656442.wasm b/shared/static/wasm/sx_browser.bc.wasm.assets/sx-3b656442.wasm new file mode 100644 index 00000000..14de5072 Binary files /dev/null and b/shared/static/wasm/sx_browser.bc.wasm.assets/sx-3b656442.wasm differ diff --git a/shared/static/wasm/sx_browser.bc.wasm.assets/sx-46414742.wasm b/shared/static/wasm/sx_browser.bc.wasm.assets/sx-46414742.wasm new file mode 100644 index 00000000..e8003fa1 Binary files /dev/null and b/shared/static/wasm/sx_browser.bc.wasm.assets/sx-46414742.wasm differ diff --git a/shared/static/wasm/sx_browser.bc.wasm.assets/sx-46cdfe5e.wasm b/shared/static/wasm/sx_browser.bc.wasm.assets/sx-46cdfe5e.wasm new file mode 100644 index 00000000..e61825a5 Binary files /dev/null and b/shared/static/wasm/sx_browser.bc.wasm.assets/sx-46cdfe5e.wasm differ diff --git a/shared/static/wasm/sx_browser.bc.wasm.assets/sx-48fa79b9.wasm b/shared/static/wasm/sx_browser.bc.wasm.assets/sx-48fa79b9.wasm new file mode 100644 index 00000000..57db9840 Binary files /dev/null and b/shared/static/wasm/sx_browser.bc.wasm.assets/sx-48fa79b9.wasm differ diff --git a/shared/static/wasm/sx_browser.bc.wasm.assets/sx-4e2acbf7.wasm b/shared/static/wasm/sx_browser.bc.wasm.assets/sx-4e2acbf7.wasm new file mode 100644 index 00000000..0a2d5d39 Binary files /dev/null and b/shared/static/wasm/sx_browser.bc.wasm.assets/sx-4e2acbf7.wasm differ diff --git a/shared/static/wasm/sx_browser.bc.wasm.assets/sx-777119c1.wasm b/shared/static/wasm/sx_browser.bc.wasm.assets/sx-777119c1.wasm new file mode 100644 index 00000000..dd509d1c Binary files /dev/null and b/shared/static/wasm/sx_browser.bc.wasm.assets/sx-777119c1.wasm differ diff --git a/shared/static/wasm/sx_browser.bc.wasm.assets/sx-85155ecd.wasm b/shared/static/wasm/sx_browser.bc.wasm.assets/sx-85155ecd.wasm new file mode 100644 index 00000000..acbd3d09 Binary files /dev/null and b/shared/static/wasm/sx_browser.bc.wasm.assets/sx-85155ecd.wasm differ diff --git a/shared/static/wasm/sx_browser.bc.wasm.assets/sx-951e6734.wasm b/shared/static/wasm/sx_browser.bc.wasm.assets/sx-951e6734.wasm new file mode 100644 index 00000000..21db8cd3 Binary files /dev/null and b/shared/static/wasm/sx_browser.bc.wasm.assets/sx-951e6734.wasm differ diff --git a/shared/static/wasm/sx_browser.bc.wasm.assets/sx-b3e92dbc.wasm b/shared/static/wasm/sx_browser.bc.wasm.assets/sx-b3e92dbc.wasm new file mode 100644 index 00000000..c08cd2b0 Binary files /dev/null and b/shared/static/wasm/sx_browser.bc.wasm.assets/sx-b3e92dbc.wasm differ diff --git a/shared/static/wasm/sx_browser.bc.wasm.assets/sx-c223a920.wasm b/shared/static/wasm/sx_browser.bc.wasm.assets/sx-c223a920.wasm new file mode 100644 index 00000000..78b01b6d Binary files /dev/null and b/shared/static/wasm/sx_browser.bc.wasm.assets/sx-c223a920.wasm differ diff --git a/shared/static/wasm/sx_browser.bc.wasm.assets/sx-c29a668e.wasm b/shared/static/wasm/sx_browser.bc.wasm.assets/sx-c29a668e.wasm new file mode 100644 index 00000000..46195904 Binary files /dev/null and b/shared/static/wasm/sx_browser.bc.wasm.assets/sx-c29a668e.wasm differ diff --git a/shared/static/wasm/sx_browser.bc.wasm.assets/sx-e28ed000.wasm b/shared/static/wasm/sx_browser.bc.wasm.assets/sx-e28ed000.wasm new file mode 100644 index 00000000..fb6707f9 Binary files /dev/null and b/shared/static/wasm/sx_browser.bc.wasm.assets/sx-e28ed000.wasm differ diff --git a/shared/static/wasm/sx_browser.bc.wasm.assets/sx-fc3f3649.wasm b/shared/static/wasm/sx_browser.bc.wasm.assets/sx-fc3f3649.wasm new file mode 100644 index 00000000..63ceb9d1 Binary files /dev/null and b/shared/static/wasm/sx_browser.bc.wasm.assets/sx-fc3f3649.wasm differ diff --git a/shared/static/wasm/sx_browser.bc.wasm.js b/shared/static/wasm/sx_browser.bc.wasm.js index 4fa08cb5..d18ee436 100644 --- a/shared/static/wasm/sx_browser.bc.wasm.js +++ b/shared/static/wasm/sx_browser.bc.wasm.js @@ -1792,7 +1792,7 @@ blake2_js_for_wasm_create: blake2_js_for_wasm_create}; } (globalThis)) -({"link":[["runtime-0db9b496",0],["prelude-d7e4b000",0],["stdlib-23ce0836",[]],["sx-64e6b16e",[2]],["jsoo_runtime-f96b44a8",[2]],["js_of_ocaml-651f6707",[2,4]],["dune__exe__Sx_browser-2ac146e9",[2,3,5]],["std_exit-10fb8830",[2]],["start-80fdb768",0]],"generated":(b=>{var +({"link":[["runtime-0db9b496",0],["prelude-d7e4b000",0],["stdlib-23ce0836",[]],["sx-951e6734",[2]],["jsoo_runtime-f96b44a8",[2]],["js_of_ocaml-651f6707",[2,4]],["dune__exe__Sx_browser-6b156118",[2,3,5]],["std_exit-10fb8830",[2]],["start-80fdb768",0]],"generated":(b=>{var c=b,a=b?.module?.export||b;return{"env":{"caml_ba_kind_of_typed_array":()=>{throw new Error("caml_ba_kind_of_typed_array not implemented")},"caml_exn_with_js_backtrace":()=>{throw new Error("caml_exn_with_js_backtrace not implemented")},"caml_int64_create_lo_mi_hi":()=>{throw new diff --git a/sx/sx/layouts.sx b/sx/sx/layouts.sx index 7000e315..c9fda679 100644 --- a/sx/sx/layouts.sx +++ b/sx/sx/layouts.sx @@ -17,8 +17,9 @@ ;; content) flows through the island, around the rocks (reactive signals). (defisland ~layouts/header (&key path) (let ((families (list "violet" "rose" "blue" "emerald" "amber" "cyan" "red" "teal" "pink" "indigo")) - (idx (signal 0)) - (shade (signal 500)) + (store (if (client?) (def-store "header-color" (fn () {:idx (signal 0) :shade (signal 500)})) nil)) + (idx (if store (get store "idx") (signal 0))) + (shade (if store (get store "shade") (signal 500))) (current-family (computed (fn () (nth families (mod (deref idx) (len families))))))) (div (~cssx/tw :tokens "block max-w-3xl mx-auto px-4 pt-8 pb-4 text-center") diff --git a/sx/sx/reactive-islands/index.sx b/sx/sx/reactive-islands/index.sx index 09ead9dc..1cbfa009 100644 --- a/sx/sx/reactive-islands/index.sx +++ b/sx/sx/reactive-islands/index.sx @@ -515,16 +515,14 @@ ;; 14. Event bridge — lake→island communication via custom DOM events (defisland ~reactive-islands/index/demo-event-bridge () - (let ((container-ref (dict "current" nil)) - (messages (signal (list))) - (_eff (schedule-idle (fn () - (let ((el (get container-ref "current"))) - (when el - (on-event el "inbox:message" - (fn (e) - (swap! messages (fn (old) - (append old (host-get (event-detail e) "text")))))))))))) - (div :ref container-ref + (let ((messages (signal (list))) + (_eff (effect (fn () + (let ((cb (host-callback + (fn (e) (swap! messages (fn (old) + (append old (host-get (event-detail e) "text")))))))) + (host-call (dom-document) "addEventListener" "inbox:message" cb) + (fn () (host-call (dom-document) "removeEventListener" "inbox:message" cb))))))) + (div (p :class "text-xs font-semibold text-stone-500 mb-2" "Event Bridge Demo") (p :class "text-sm text-stone-600 mb-2" "The buttons below simulate server-rendered content dispatching events into the island.") diff --git a/tests/playwright/demo-interactions.spec.js b/tests/playwright/demo-interactions.spec.js index ca4f2678..eae8ca4b 100644 --- a/tests/playwright/demo-interactions.spec.js +++ b/tests/playwright/demo-interactions.spec.js @@ -232,8 +232,7 @@ test.describe('Reactive island interactions', () => { } }); - test.fixme('event-bridge: sender triggers receiver update', async ({ page }) => { - // BUG: on-event handler receives CustomEvent but swap!/signal update doesn't propagate to DOM + test('event-bridge: sender triggers receiver update', async ({ page }) => { await page.goto(BASE_URL + '/sx/(geography.(reactive.(examples.event-bridge-demo)))', { waitUntil: 'networkidle' }); await page.waitForTimeout(2000); diff --git a/tests/playwright/isomorphic.spec.js b/tests/playwright/isomorphic.spec.js index 7d976326..45d5a101 100644 --- a/tests/playwright/isomorphic.spec.js +++ b/tests/playwright/isomorphic.spec.js @@ -177,7 +177,7 @@ test.describe('Isomorphic SSR', () => { }); test.fixme('navigation preserves header island state', async ({ page }) => { - // BUG: header island inside #main-panel swap boundary — needs structural layout change or store-based state + // BUG: def-store state not persisting — *store-registry* likely reset during SPA nav component reload await page.goto(BASE_URL + '/sx/', { waitUntil: 'networkidle' }); // Wait for header island to hydrate