Skip to content

Commit

Permalink
FEAT/patching dom added
Browse files Browse the repository at this point in the history
  • Loading branch information
AugustinSorel committed Jan 11, 2024
1 parent 29c067a commit 91ff93a
Show file tree
Hide file tree
Showing 10 changed files with 759 additions and 97 deletions.
8 changes: 4 additions & 4 deletions example/counter/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/preset-env": "^7.23.7",
"@babel/preset-env": "^7.23.8",
"@babel/preset-typescript": "^7.23.3",
"@babel/register": "^7.23.7",
"@types/node": "^20.10.6",
"css-loader": "^6.8.1",
"@types/node": "^20.10.8",
"css-loader": "^6.9.0",
"html-webpack-plugin": "^5.6.0",
"rollup-plugin-dts": "^6.1.0",
"style-loader": "^3.3.3",
"style-loader": "^3.3.4",
"ts-loader": "^9.5.1",
"webpack": "^5.89.0",
"webpack-cli": "^5.1.4",
Expand Down
2 changes: 0 additions & 2 deletions packages/runtime/rollup.config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import cleanup from "rollup-plugin-cleanup";
import filesize from "rollup-plugin-filesize";
import typescript from "@rollup/plugin-typescript";
import dts from "rollup-plugin-dts";

Expand All @@ -13,7 +12,6 @@ const config: RollupOptions[] = [
{
file: "dist/index.js",
format: "esm",
plugins: [filesize()],
},
],
},
Expand Down
7 changes: 4 additions & 3 deletions packages/runtime/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,10 @@ export const createApp = <TState, TReducers extends Reducers<TState>>({
};

const renderApp = () => {
const newVdom = view(state, emit);

vdom = patchDom(vdom, newVdom, parentEl);
if (vdom && parentEl) {
const newVdom = view(state, emit);
vdom = patchDom(vdom, newVdom, parentEl);
}
};

const subscriptions = [dispatcher.afterEveryCommand(renderApp)];
Expand Down
6 changes: 2 additions & 4 deletions packages/runtime/src/destroy-dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,7 @@ const destroyFragmentNode = (fragmentNode: HFragment) => {
};

const destroyPortalNode = (portalNode: HPortal) => {
if (!portalNode.children) {
return;
for (const children of portalNode.children) {
destroyDom(children);
}

destroyDom(portalNode.children);
};
2 changes: 1 addition & 1 deletion packages/runtime/src/events.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { H } from "./h";

export const addEventListener = (
eventName: keyof HTMLElementEventMap,
eventName: string,
handler: Parameters<HTMLElement["addEventListener"]>[1],
el: HTMLElement,
) => {
Expand Down
22 changes: 20 additions & 2 deletions packages/runtime/src/h.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export type HFragment = {
export type HPortal = {
type: "portal";

children: VNodes | null;
children: VNodes[];
domPointer: HTMLElement;
};

Expand Down Expand Up @@ -76,7 +76,25 @@ export const hPortal = (
): HPortal => {
return {
type: "portal",
children,
children: [children].filter(removeNull),
domPointer: targetEl,
};
};

export function extractChildren(vdom: HFragment | HPortal | H) {
if (vdom.children == null) {
return [];
}

const children: VNodes[] = [];

for (const child of vdom.children) {
if (child.type === "fragment") {
children.push(...extractChildren(child));
} else {
children.push(child);
}
}

return children;
}
67 changes: 50 additions & 17 deletions packages/runtime/src/mount-dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,51 +2,61 @@ import { setAttributes } from "./attributes";
import { addEventListeners } from "./events";
import { HString, VNodes, H, HFragment } from "./h";

export const mountDOM = (vdom: VNodes, parentEl: HTMLElement) => {
export const mountDOM = (
vdom: VNodes,
parentEl: HTMLElement,
index?: number,
) => {
if (vdom.type === "text") {
createTextNode(vdom, parentEl);
createTextNode(vdom, parentEl, index);
return;
}

if (vdom.type === "fragment") {
createFragmentNode(vdom, parentEl);
createFragmentNode(vdom, parentEl, index);
return;
}

if (vdom.type === "element") {
createElementNode(vdom, parentEl);
createElementNode(vdom, parentEl, index);
return;
}

if (vdom.type === "portal") {
if (!vdom.children) {
return;
}

mountDOM(vdom.children, vdom.domPointer);
vdom.children.forEach((children, i) => {
mountDOM(children, parentEl, index ? index + i : undefined);
});
return;
}

throw new Error(`vdom type: ${JSON.stringify(vdom)} is not being handle`);
};

const createTextNode = (vdom: HString, parentEl: HTMLElement) => {
const createTextNode = (
vdom: HString,
parentEl: HTMLElement,
index?: number,
) => {
const textNode = document.createTextNode(vdom.value);

vdom.domPointer = textNode;

parentEl.append(textNode);
insert(textNode, parentEl, index);
};

const createFragmentNode = (vdom: HFragment, parentEl: HTMLElement) => {
const createFragmentNode = (
vdom: HFragment,
parentEl: HTMLElement,
index?: number,
) => {
vdom.domPointer = parentEl;

for (const children of vdom.children) {
mountDOM(children, parentEl);
}
vdom.children.forEach((children, i) => {
mountDOM(children, parentEl, index ? index + i : undefined);
});
};

const createElementNode = (vdom: H, parentEl: HTMLElement) => {
const createElementNode = (vdom: H, parentEl: HTMLElement, index?: number) => {
const { tagName, props, children } = vdom;
const { on: events, ...attrs } = props;

Expand All @@ -61,5 +71,28 @@ const createElementNode = (vdom: H, parentEl: HTMLElement) => {
mountDOM(child, element);
}

parentEl.append(element);
insert(element, parentEl, index);
};

export const insert = (
el: HTMLElement | Text,
parentEl: HTMLElement,
index?: number,
) => {
if (index == null) {
parentEl.append(el);
return;
}

if (index < 0) {
throw new Error(`Index must be a positive integer, got ${index}`);
}

const children = parentEl.childNodes;

if (index >= children.length) {
parentEl.append(el);
} else {
parentEl.insertBefore(el, children[index]);
}
};
Loading

0 comments on commit 91ff93a

Please sign in to comment.