diff --git a/src/lib/YarJS.ts b/src/lib/YarJS.ts index c2bb31e..b441326 100644 --- a/src/lib/YarJS.ts +++ b/src/lib/YarJS.ts @@ -124,6 +124,14 @@ function updateDom( }); } +function commitDeletion(fiber: YarFiber, domParent: HTMLElement | Text) { + if (fiber.dom) { + domParent.removeChild(fiber.dom); + } else { + commitDeletion(fiber.child!, domParent); + } +} + /** * Actually commit the processed Fiber to the real DOM * @param fiber - The Fiber Element to process @@ -131,14 +139,23 @@ function updateDom( function commitWork(fiber: YarFiber | null) { if (!fiber) return; - const domParent = fiber.parent!.dom!; + // we can have fibers without dom nodes, + // so we search for the first parent with one + let parentFiber = fiber.parent!; + while (!parentFiber.dom) { + parentFiber = parentFiber.parent!; + } + + const domParent = parentFiber.dom!; switch (fiber.effectTag) { case YarEffectTag.Placement: - domParent.appendChild(fiber.dom!); + if (fiber.dom) { + domParent.appendChild(fiber.dom); + } break; case YarEffectTag.Deletion: - domParent.removeChild(fiber.dom!); + commitDeletion(fiber, domParent); break; case YarEffectTag.Update: updateDom(fiber.dom!, fiber.alternate!.props, fiber.props); @@ -159,6 +176,26 @@ function commitRoot() { WIP_ROOT = null; } +function updateFunctionComponent(fiber: YarFiber) { + // the fiber from a function component doesn’t have a DOM node + // and the children come from running the function instead of getting them directly from the props + + if (!(fiber.type instanceof Function)) return; + + const children = [fiber.type(fiber.props)]; + reconcileChildren(fiber, children); +} + +function updateNativeComponent(fiber: YarFiber) { + if (!fiber.dom) { + // Create the actual dom element + fiber.dom = generateDomNode(fiber); + } + + // Create a new fiber for each child + reconcileChildren(fiber, fiber.props.children); +} + /** * Process the Fiber Tree, this is a representation of the DOM * Since this process could be interrupted before the whole @@ -168,14 +205,12 @@ function commitRoot() { * @param fiber - The Fiber to process */ function processFiber(fiber: YarFiber): YarFiber | undefined { - if (!fiber.dom) { - // Create the actual dom element - fiber.dom = generateDomNode(fiber); + if (fiber.type instanceof Function) { + updateFunctionComponent(fiber); + } else { + updateNativeComponent(fiber); } - // Create a new fiber for each child - reconcileChildren(fiber, fiber.props.children); - // Search for the new fiber that needs to be processed if (fiber.child) { // return the first child of the current fiber diff --git a/src/lib/YarJs.interfaces.ts b/src/lib/YarJs.interfaces.ts index a9ded1d..2fbe800 100644 --- a/src/lib/YarJs.interfaces.ts +++ b/src/lib/YarJs.interfaces.ts @@ -1,4 +1,7 @@ -export type YarHTMLTagName = keyof React.JSX.IntrinsicElements | string; +export type YarHTMLTagName = + | keyof React.JSX.IntrinsicElements + | string + | Function; export enum YarEffectTag { Update, diff --git a/src/main.tsx b/src/main.tsx index 8b2392e..1e4e2cf 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -3,19 +3,9 @@ import { render } from "./lib/YarJS"; const root = document.querySelector("#app")!; -const rerender = (value: string) => { - const onChange = (e: React.FormEvent) => { - rerender(e.currentTarget.value); - }; +function App(props) { + return

Hi {props.name}

; +} - const element = ( -
- -

Hello {value}

-
- ); - - render(element, root); -}; - -rerender("foo"); +const element = ; +render(element, root);