a small incremental UI library for the web
javascript web ui
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Commit to DOM

garrison 13b2f463 8ef4c226

+86 -12
+50
js/commit.ts
··· 1 + import { HostFiber } from './fiber.ts'; 2 + 3 + export function commit(commitFiber) { 4 + let fiber = commitFiber; 5 + while (fiber) { 6 + commitWork(fiber); 7 + 8 + if (fiber.child) fiber = fiber.child; 9 + else if (fiber.sibling) fiber = fiber.sibling; 10 + else fiber = fiber.parent?.sibling; 11 + } 12 + } 13 + 14 + function commitWork(fiber) { 15 + if (fiber.tag == HostFiber) { 16 + if (fiber.effect === 'placement') commitPlacement(fiber); 17 + else commitUpdate(fiber); 18 + } 19 + } 20 + 21 + function commitPlacement(fiber) { 22 + const domParent = findDomParent(fiber); 23 + const domSibling = findNextExistingDomSibling(fiber); 24 + 25 + const domElement = document.createElement(fiber.type); 26 + fiber.dom = domElement; 27 + 28 + if (domSibling) domParent.insertBefore(domElement, domSibling); 29 + else domParent.appendChild(domElement); 30 + } 31 + 32 + function commitUpdate(fiber) { 33 + } 34 + 35 + function findDomParent(forFiber) { 36 + let fiber = forFiber.parent; 37 + while (fiber) { 38 + if (fiber.dom) return fiber.dom; 39 + fiber = fiber.parent; 40 + } 41 + throw new Error(`Could not find parent for fiber ${forFiber}`); 42 + } 43 + 44 + function findNextExistingDomSibling(forFiber) { 45 + return null; 46 + } 47 + 48 + function isHost(fiber) { 49 + return fiber.tag == HostFiber; 50 + }
+27 -9
js/fiber.ts
··· 1 - export function makeFiber() { 1 + export const HostFiber = 'host'; 2 + 3 + export function makeFiber(tag) { 2 4 return { 5 + tag: tag, 3 6 type: null, 4 7 props: null, 5 8 ··· 30 33 31 34 let firstNewChild = null; 32 35 let prevChild; 36 + let lastKeptIndex = 0; 33 37 for (let i = 0; i < elements.length; i++) { 34 38 const el = elements[i]; 35 39 const key = el.key || i; 36 - const oldFiber = oldFiberLookup.get(key); 37 - const newFiber = update(oldFiberLookup, el, i); 40 + const oldFiber = oldFiberLookup.get(key) || null; 41 + oldFiberLookup.delete(key); 42 + const newFiber = update(oldFiber, el, i); 38 43 39 - // TODO: placement 44 + newFiber.parent = parentFiber; 40 45 newFiber.index = i; 41 - console.log(oldFiber, newFiber); 46 + newFiber.alternate = oldFiber; 47 + if (oldFiber) { 48 + const oldIndex = oldFiber.index; 49 + if (oldIndex < lastKeptIndex) { 50 + newFiber.effect = 'placement'; 51 + } 52 + else { 53 + lastKeptIndex = i; 54 + } 55 + } 56 + else { 57 + newFiber.effect = 'placement'; 58 + } 42 59 43 60 if (prevChild) prevChild.sibling = newFiber; 44 61 else firstNewChild = newFiber; ··· 52 69 if (typeof element == 'object') { 53 70 return updateElement(oldFiber, element, index); 54 71 } 72 + // TODO: text nodes 55 73 return null; 56 74 } 57 75 58 76 function updateElement(oldFiber, element, index) { 59 77 if (oldFiber === null || oldFiber.type !== element.type) { 60 - const newFiber = makeFiber(); 78 + const newFiber = makeFiber(HostFiber); 61 79 newFiber.type = element.type; 62 80 newFiber.props = element.props; 63 81 return newFiber; 64 82 } 65 83 else { 66 - const newFiber = oldFiber.alternate || makeFiber(); 84 + // TODO: clone alternate 85 + const newFiber = makeFiber(HostFiber); 67 86 newFiber.props = element.props; 68 87 return newFiber; 69 88 } ··· 73 92 const lookup = new Map(); 74 93 75 94 let fiber = childFiber; 76 - let i = 0; 77 95 while (fiber) { 78 - key = fiber.key || i; 96 + key = fiber.key || fiber.index; 79 97 lookup.set(key, fiber); 80 98 fiber = fiber.sibling; 81 99 }
+8 -2
js/noir.ts
··· 1 1 import { makeFiber, reconcileChildren } from './fiber.ts'; 2 + import { commit } from './commit.ts'; 2 3 3 4 export function createElement(type, props, ...children) { 4 5 return { ··· 10 11 }; 11 12 } 12 13 14 + let wipRootFiber; 13 15 let nextFiber; 14 16 15 17 export function render(element, container) { 16 - const rootFiber = makeFiber(); 18 + const rootFiber = makeFiber('root'); 17 19 rootFiber.type = 'root'; 18 20 rootFiber.dom = container; 19 21 rootFiber.props = { children: [element] }; 20 22 23 + wipRootFiber = rootFiber; 21 24 nextFiber = rootFiber; 22 25 performWork(); 23 26 } 24 27 25 28 function performWork() { 26 - if (!nextFiber) return; 29 + if (!nextFiber) { 30 + commit(wipRootFiber); 31 + return; 32 + } 27 33 28 34 nextFiber = renderFiber(nextFiber); 29 35 performWork();
+1 -1
priv/static/todo.html
··· 1 1 <!doctype html> 2 2 <html> 3 3 <head> 4 - <script src="/assets/js/todo.js"></script> 4 + <script defer src="/assets/js/todo.js"></script> 5 5 </head> 6 6 <body> 7 7 <div id="root" />