import gleam/dynamic.{type Dynamic} import redraw.{type Element, type ReactComponent} import redraw/dom.{type Error} import redraw/internal/unsafe /// Root to display React DOM. /// /// [Documentation](https://react.dev/reference/react-dom/client/createRoot#createroot) pub type Root /// Let you create a root to display React components inside a browser DOM node. /// Contrarily to JavaScript, `create_root` returns a `Result` to avoid runtime /// error. Indeed, when the provided root does not exist in your HTML, `create_root` /// fails. You should never assume `create_root` will work out-of-the-box when /// you're building a library. Otherwise, you could assert the resulting /// value in your application. /// /// ```gleam /// import redraw/dom/client /// /// pub fn main() { /// let assert Ok(root) = client.create_root("app") /// client.render(root, app()) /// } /// ``` /// /// [Documentation](https://react.dev/reference/react-dom/client/createRoot) @external(javascript, "./client.ffi.mjs", "createRoot") pub fn create_root(root: String) -> Result(Root, Error) /// Creates an HTML Element and attach a root on it. /// This creates a "virtual" root, in the sense that the root will not be attached /// to the real DOM. It let you attach and render some component to the root, while /// providing the HTML Element on which the root is attached. That let you use /// all Web API on that node, like reading inner HTML or stuff. /// /// For example, rendering a React Component tree as a string [is recommended /// with a virtual root](https://react.dev/reference/react-dom/server/renderToString#removing-rendertostring-from-the-client-code). /// /// The first `Dynamic` value is the created HTML Element (a basic `div`), and /// the second value is the created root. /// /// [Documentation](https://react.dev/reference/react-dom/client/createRoot) @external(javascript, "./client.ffi.mjs", "virtualRoot") pub fn virtual_root() -> #(Dynamic, Root) /// Let you display React components inside a browser DOM node whose HTML content /// was previously generated by `react-dom/server`. /// Contrarily to JavaScript, `hydrate_root` returns a `Result` to avoid runtime /// error. Indeed, when the provided root does not exist in your HTML, `hydrate_root` /// fails. You should never assume `hydrate_root` will work out-of-the-box when /// you're building a library. Otherwise, you could assert the resulting /// value in your application. /// /// ```gleam /// import redraw/dom/client /// /// pub fn main() { /// let assert Ok(root) = client.hydrate_root("app") /// } /// ``` /// /// [Documentation](https://react.dev/reference/react-dom/client/hydrateRoot) @external(javascript, "./client.ffi.mjs", "hydrateRoot") pub fn hydrate_root(root: String, node: Element) -> Result(Root, Error) /// Call `render(root)` to display a piece of JSX (“React node”) into the React /// root’s browser DOM node. /// /// [Documentation](https://react.dev/reference/react-dom/client/createRoot#root-render) @deprecated("Components in Redraw have changed. Use `render_` instead") pub fn render(root: Root, child: Element) -> Nil { do_render(root, child) } /// Call `render(root)` to display a piece of JSX (“React node”) into the React /// root’s browser DOM node. /// /// [Documentation](https://react.dev/reference/react-dom/client/createRoot#root-render) pub fn render_( root: Root, child: ReactComponent(Nil), return: fn(fn(Nil) -> Element) -> Element, ) -> Nil { unsafe.coerce({ use child <- redraw.compose(child) let children = return(child) do_render(root, children) |> unsafe.coerce }) } @external(javascript, "./client.ffi.mjs", "render") fn do_render(root: Root, child: Element) -> Nil /// Call `unmount(root)` to destroy a rendered tree inside a React root. /// /// An app fully built with React will usually not have any calls to `unmount`. /// /// This is mostly useful if your React root’s DOM node (or any of its ancestors) /// may get removed from the DOM by some other code. For example, imagine a /// jQuery tab panel that removes inactive tabs from the DOM. If a tab gets /// removed, everything inside it (including the React roots inside) would get /// removed from the DOM as well. In that case, you need to tell React to “stop” /// managing the removed root’s content by calling root.unmount. Otherwise, the /// components inside the removed root won’t know to clean up and free up global /// resources like subscriptions. /// /// Calling root.unmount will unmount all the components in the root and “detach” /// React from the root DOM node, including removing any event handlers or state /// in the tree. /// /// [Documentation](https://react.dev/reference/react-dom/client/createRoot#root-unmount) @external(javascript, "./client.ffi.mjs", "unmount") pub fn unmount(root: Root) -> Nil