runner.sx: Converted define forms inside island body to letrec. Multiple define forms in a let body cause render-to-dom to fall back to eval-expr for the whole body, which evaluates (div ...) as a list instead of rendering it to DOM. letrec keeps the last body expression (div) as the render target. sx_browser.ml: js_to_value now stores plain JS functions as host objects (Dict with __host_handle) instead of wrapping as NativeFn. This preserves the original JS function identity through the SX→JS round-trip, keeping _driveAsync wrappers from host-callback intact when passed to addEventListener via host-call. Remaining: IO suspension in click handler is caught as "IO suspension in non-IO context" instead of being driven by _driveAsync. The host-callback wrapper creates the right JS function, but the event dispatch path doesn't go through K.callFn. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
51 KiB
51 KiB