From bf125e9ed324a17c5a9ab6fcd816f8476ae81177 Mon Sep 17 00:00:00 2001 From: Guillaume Hivert Date: Thu, 18 Jul 2024 17:52:06 +0200 Subject: [PATCH] Add ability to add children --- src/main.ffi.mjs | 29 ++++++++++++++++++++++++----- src/main.gleam | 47 +++++++++++++++++++++++++++++++++-------------- src/main.jsx | 39 +++++++++++++++++++++++++-------------- 3 files changed, 82 insertions(+), 33 deletions(-) diff --git a/src/main.ffi.mjs b/src/main.ffi.mjs index 5515ac4..eede45b 100644 --- a/src/main.ffi.mjs +++ b/src/main.ffi.mjs @@ -1,6 +1,7 @@ import React, { useEffect } from "react"; -import runtime from "react/jsx-runtime"; +import * as gleam from "./gleam.mjs"; import ReactDOM from "react-dom/client"; +import runtime from "react/jsx-runtime"; export function createRoot(value) { const node = document.getElementById(value); @@ -11,10 +12,23 @@ export function render(root, children) { return root.render(children); } +// Extract children from props to give it to function. +export function addProxy(val) { + return new Proxy(val, { + apply(target, thisArg, argumentsList) { + const props = argumentsList[0]; + return target(props, gleam.List.fromArray(props.children)); + }, + }); +} + +// Generate JSX export function jsx(value, props_, children_) { if (value === "text_") return children_; let children = children_?.toArray() ?? []; let isStatic = true; + + // Keyed elements if (Array.isArray(children[0])) { children = children.map((c) => { const [key, node] = c; @@ -23,6 +37,8 @@ export function jsx(value, props_, children_) { }); isStatic = false; } + + // Generate correct props const props = {}; Object.assign(props, props_); if (children.length > 0) props.children = children; @@ -41,13 +57,16 @@ export function useTimeout(setter) { }, []); } -export function useHelloEffect(deps) { +export function useHelloEffect(deps, content) { useEffect(() => { - console.log("hello"); - console.log(""); + console.log("hello", content); }, deps.toArray()); } export function strictMode(children) { - return jsx(React.StrictMode, { children: children.toArray() }); + return jsx(React.StrictMode, {}, children); +} + +export function fragment(children) { + return jsx(React.Fragment, {}, children); } diff --git a/src/main.gleam b/src/main.gleam index 1ab20dd..caec02c 100644 --- a/src/main.gleam +++ b/src/main.gleam @@ -1,6 +1,7 @@ import gleam/dynamic import gleam/int import gleam/io +import gleam/list pub type Root @@ -19,16 +20,35 @@ fn render(root: Root, children: Component) -> Nil @external(javascript, "./main.ffi.mjs", "jsx") fn jsx(value: a, props: b, children: c) -> Component +@external(javascript, "./main.ffi.mjs", "fragment") +fn fragment(children: List(Component)) -> Component + pub fn main() { let root = root() create_root("root") - |> render(root([])) + |> render(strict_mode([root([])])) // |> render(children()) } @external(javascript, "./main.ffi.mjs", "strictMode") pub fn strict_mode(children: List(Component)) -> Component +@external(javascript, "./main.ffi.mjs", "addProxy") +fn add_proxy( + a: fn(props, List(Component)) -> Component, +) -> fn(props, List(Component)) -> Component + +pub fn component( + name: String, + component: fn(props, List(Component)) -> Component, +) -> fn(props, List(Component)) -> Component { + let component = + component + |> add_proxy + |> set_function_name(name) + fn(props, children) { jsx(component, props, children) } +} + pub type Props { Props } @@ -63,7 +83,7 @@ pub fn text(content) -> Component { @external(javascript, "./main.ffi.mjs", "setFunctionName") fn set_function_name(a: a, name: String) -> a -pub fn component( +pub fn component_( name: String, val: fn(props) -> Component, ) -> fn(props) -> Component { @@ -81,18 +101,15 @@ fn use_state_(default: a) -> #(a, fn(fn(a) -> a) -> Nil) fn use_timeout(default: fn() -> Nil) -> Nil @external(javascript, "./main.ffi.mjs", "useHelloEffect") -fn use_hello_effect(deps: List(a)) -> Nil +fn use_hello_effect(deps: List(a), content: String) -> Nil pub fn root() { let inside = mk_inside() - use props <- component("Root") + use props <- component_("Root") let #(state, set_state) = use_state_(0) - use_timeout(fn() { - use state <- set_state() - state + 1 - }) - use_hello_effect([]) - strict_mode([app(), inside(InsideProps(state))]) + use_hello_effect([], "root") + use_timeout(fn() { set_state(fn(state) { state + 1 }) }) + fragment([app(), inside(InsideProps(state))]) } pub type InsideProps { @@ -101,14 +118,16 @@ pub type InsideProps { pub fn mk_inside() { let inside = mk_inside_help() - use props: InsideProps <- component("Insider") + use props: InsideProps <- component_("Insider") + use_hello_effect([], "inside") keyed(div([], _), [ - #("inside", inside(props)), + #("inside", inside(props, [div([], [text("From Children!")])])), #("text", div([], [text("inside " <> int.to_string(props.count))])), ]) } pub fn mk_inside_help() { - use props: InsideProps <- component("InsiderHelp") - div([], [text("inside " <> int.to_string(props.count))]) + use props: InsideProps, children <- component("InsiderHelp") + use_hello_effect([], "inside_help") + div([], [text("inside " <> int.to_string(props.count)), fragment(children)]) } diff --git a/src/main.jsx b/src/main.jsx index 06952bb..8518b3b 100644 --- a/src/main.jsx +++ b/src/main.jsx @@ -1,32 +1,43 @@ -import React from "react"; +import React, { useEffect } from "react"; import ReactDOM from "react-dom/client"; -import App from "./App.jsx"; import "./index.css"; ReactDOM.createRoot(document.getElementById("root")).render( - - , ); +export function useHelloEffect(content) { + useEffect(() => { + console.log("hello", content); + }, [content]); +} + +export function App() { + useHelloEffect("app"); + return ; +} + export function Test() { - return ( -
- Muf - Muf - Muf - Muf -
- ); + useHelloEffect("test"); + return ; + // return ( + //
+ // Muf + // Muf + // Muf + // Muf + //
+ // ); } export function Test21() { + useHelloEffect("Test21"); return (
- {new Array(5).fill(0).map(() => ( - Mumuf + {new Array(5).fill(0).map((_, index) => ( + Mumuf ))}
);