forgo-state
Advanced tools
Comparing version 0.0.12 to 0.0.13
@@ -40,69 +40,35 @@ "use strict"; | ||
// concat latest updates with pending updates. | ||
const argsToUpdatePlusPendingArgs = argsListToUpdate.concat(argsToRenderInTheNextCycle); | ||
// make a map, of node => all args attached to node | ||
const argsListMap = new Map(); | ||
for (const args of argsToUpdatePlusPendingArgs) { | ||
if (args.element.node) { | ||
const state = forgo_1.getForgoState(args.element.node); | ||
if (state) { | ||
const componentState = state.components[args.element.componentIndex]; | ||
if (componentState.numNodes === 1) { | ||
let entry = argsListMap.get(args.element.node); | ||
if (!entry) { | ||
entry = []; | ||
argsListMap.set(args.element.node, entry); | ||
} | ||
entry.push(args); | ||
} | ||
// This component rendered a fragment or an array | ||
else { | ||
const parentElement = args.element.node | ||
.parentElement; | ||
const childNodes = Array.from(parentElement.childNodes); | ||
const nodeIndex = childNodes.findIndex((x) => x === args.element.node); | ||
const nodes = childNodes.slice(nodeIndex, nodeIndex + componentState.numNodes); | ||
for (const node of nodes) { | ||
let entry = argsListMap.get(node); | ||
if (!entry) { | ||
entry = []; | ||
argsListMap.set(node, entry); | ||
} | ||
entry.push(args); | ||
} | ||
} | ||
const argsToUpdatePlusPendingArgs = argsToRenderInTheNextCycle.concat(argsListToUpdate.filter((x) => !argsToRenderInTheNextCycle.includes(x))); | ||
const componentStatesAndArgs = argsToUpdatePlusPendingArgs.map((x) => { | ||
const state = forgo_1.getForgoState(x.element.node); | ||
if (!state) { | ||
throw new Error("Missing state on node."); | ||
} | ||
else { | ||
return [state.components[x.element.componentIndex], x]; | ||
} | ||
}); | ||
// If a parent component is already rerendering, | ||
// don't queue the child rerender. | ||
const componentsToUpdate = componentStatesAndArgs.filter((item) => { | ||
const [componentState, args] = item; | ||
let node = args.element.node; | ||
let state = forgo_1.getForgoState(node); | ||
let parentStates = state.components.slice(0, args.element.componentIndex); | ||
while (node && state) { | ||
if (parentStates.some((x) => componentStatesAndArgs.some(([compStateInArray]) => compStateInArray.component === x.component))) { | ||
return false; | ||
} | ||
} | ||
} | ||
// Now for each node, find the args with the lowest componentIndex | ||
// Rendering the component with the lowest componentIndex | ||
// The higher up components get rendered automatically. | ||
const argsListWithMinComponentIndex = []; | ||
for (const entries of argsListMap) { | ||
let argsWithMinComponentIndex = undefined; | ||
const [node, argsList] = entries; | ||
for (const args of argsList) { | ||
if (argsWithMinComponentIndex) { | ||
if (args.element.componentIndex < | ||
argsWithMinComponentIndex.element.componentIndex) { | ||
argsWithMinComponentIndex = args; | ||
node = node.parentElement; | ||
if (node) { | ||
state = forgo_1.getForgoState(node); | ||
if (state) { | ||
parentStates = state.components.filter((x) => x !== componentState); | ||
} | ||
} | ||
else { | ||
argsWithMinComponentIndex = args; | ||
} | ||
} | ||
if (argsWithMinComponentIndex) { | ||
argsListWithMinComponentIndex.push([node, argsWithMinComponentIndex]); | ||
} | ||
} | ||
// 1. We gotta find if a node is a child of another node pending rerender | ||
// If so, there's no need to render the descendant node. | ||
// 2. Also, if a component renders multiple nodes, include only the root node. | ||
const justTheNodes = argsListWithMinComponentIndex | ||
.map(([node]) => node) | ||
.filter((x) => x); | ||
const argsListOfParentNodes = argsListWithMinComponentIndex.filter(([node, args]) => !justTheNodes.some((x) => x !== node && x.contains(node)) && | ||
node === args.element.node); | ||
return true; | ||
}); | ||
argsToRenderInTheNextCycle.length = 0; | ||
for (const [node, args] of argsListOfParentNodes) { | ||
for (const [, args] of componentsToUpdate) { | ||
argsToRenderInTheNextCycle.push(args); | ||
@@ -109,0 +75,0 @@ } |
{ | ||
"name": "forgo-state", | ||
"version": "0.0.12", | ||
"version": "0.0.13", | ||
"main": "./dist", | ||
@@ -11,3 +11,3 @@ "author": "Jeswin Kumar<jeswinpk@agilehead.com>", | ||
"dependencies": { | ||
"forgo": "^0.0.36" | ||
"forgo": "^0.0.39" | ||
}, | ||
@@ -14,0 +14,0 @@ "devDependencies": { |
121
src/index.ts
@@ -7,2 +7,4 @@ import { | ||
getForgoState, | ||
NodeAttachedComponentState, | ||
NodeAttachedState, | ||
} from "forgo"; | ||
@@ -69,88 +71,55 @@ | ||
// concat latest updates with pending updates. | ||
const argsToUpdatePlusPendingArgs = argsListToUpdate.concat( | ||
argsToRenderInTheNextCycle | ||
const argsToUpdatePlusPendingArgs = argsToRenderInTheNextCycle.concat( | ||
argsListToUpdate.filter((x) => !argsToRenderInTheNextCycle.includes(x)) | ||
); | ||
// make a map, of node => all args attached to node | ||
const argsListMap = new Map<ChildNode, ForgoRenderArgs[]>(); | ||
for (const args of argsToUpdatePlusPendingArgs) { | ||
if (args.element.node) { | ||
const state = getForgoState(args.element.node); | ||
if (state) { | ||
const componentState = | ||
state.components[args.element.componentIndex]; | ||
if (componentState.numNodes === 1) { | ||
let entry = argsListMap.get(args.element.node); | ||
if (!entry) { | ||
entry = []; | ||
argsListMap.set(args.element.node, entry); | ||
} | ||
entry.push(args); | ||
} | ||
// This component rendered a fragment or an array | ||
else { | ||
const parentElement: HTMLElement = args.element.node | ||
.parentElement as HTMLElement; | ||
const childNodes = Array.from(parentElement.childNodes); | ||
const nodeIndex = childNodes.findIndex( | ||
(x) => x === args.element.node | ||
); | ||
const nodes = childNodes.slice( | ||
nodeIndex, | ||
nodeIndex + componentState.numNodes | ||
); | ||
for (const node of nodes) { | ||
let entry = argsListMap.get(node); | ||
if (!entry) { | ||
entry = []; | ||
argsListMap.set(node, entry); | ||
} | ||
entry.push(args); | ||
} | ||
} | ||
} | ||
const componentStatesAndArgs: [ | ||
NodeAttachedComponentState<any>, | ||
ForgoRenderArgs | ||
][] = argsToUpdatePlusPendingArgs.map((x) => { | ||
const state = getForgoState(x.element.node as ChildNode); | ||
if (!state) { | ||
throw new Error("Missing state on node."); | ||
} else { | ||
return [state.components[x.element.componentIndex], x]; | ||
} | ||
} | ||
}); | ||
// Now for each node, find the args with the lowest componentIndex | ||
// Rendering the component with the lowest componentIndex | ||
// The higher up components get rendered automatically. | ||
const argsListWithMinComponentIndex: [ChildNode, ForgoRenderArgs][] = []; | ||
// If a parent component is already rerendering, | ||
// don't queue the child rerender. | ||
const componentsToUpdate = componentStatesAndArgs.filter((item) => { | ||
const [componentState, args] = item; | ||
for (const entries of argsListMap) { | ||
let argsWithMinComponentIndex: ForgoRenderArgs | undefined = undefined; | ||
const [node, argsList] = entries; | ||
for (const args of argsList) { | ||
if (argsWithMinComponentIndex) { | ||
if ( | ||
args.element.componentIndex < | ||
argsWithMinComponentIndex.element.componentIndex | ||
) { | ||
argsWithMinComponentIndex = args; | ||
let node: ChildNode | null = args.element.node as ChildNode; | ||
let state: NodeAttachedState | undefined = getForgoState(node); | ||
let parentStates = (state as NodeAttachedState).components.slice( | ||
0, | ||
args.element.componentIndex | ||
); | ||
while (node && state) { | ||
if ( | ||
parentStates.some((x) => | ||
componentStatesAndArgs.some( | ||
([compStateInArray]) => | ||
compStateInArray.component === x.component | ||
) | ||
) | ||
) { | ||
return false; | ||
} | ||
node = node.parentElement; | ||
if (node) { | ||
state = getForgoState(node); | ||
if (state) { | ||
parentStates = state.components.filter( | ||
(x) => x !== componentState | ||
); | ||
} | ||
} else { | ||
argsWithMinComponentIndex = args; | ||
} | ||
} | ||
if (argsWithMinComponentIndex) { | ||
argsListWithMinComponentIndex.push([node, argsWithMinComponentIndex]); | ||
} | ||
} | ||
return true; | ||
}); | ||
// 1. We gotta find if a node is a child of another node pending rerender | ||
// If so, there's no need to render the descendant node. | ||
// 2. Also, if a component renders multiple nodes, include only the root node. | ||
const justTheNodes = argsListWithMinComponentIndex | ||
.map(([node]) => node) | ||
.filter((x) => x) as ChildNode[]; | ||
const argsListOfParentNodes = argsListWithMinComponentIndex.filter( | ||
([node, args]) => | ||
!justTheNodes.some((x) => x !== node && x.contains(node)) && | ||
node === args.element.node | ||
); | ||
argsToRenderInTheNextCycle.length = 0; | ||
for (const [node, args] of argsListOfParentNodes) { | ||
for (const [, args] of componentsToUpdate) { | ||
argsToRenderInTheNextCycle.push(args); | ||
@@ -157,0 +126,0 @@ } |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
22512
355
+ Addedforgo@0.0.39(transitive)
- Removedforgo@0.0.36(transitive)
Updatedforgo@^0.0.39