@b9g/crank 0.7.1 → 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +522 -79
- package/async.cjs +42 -38
- package/async.cjs.map +1 -1
- package/async.d.ts +10 -7
- package/async.js +42 -38
- package/async.js.map +1 -1
- package/crank.cjs +50 -8
- package/crank.cjs.map +1 -1
- package/crank.js +50 -8
- package/crank.js.map +1 -1
- package/package.json +2 -1
- package/umd.js +50 -8
- package/umd.js.map +1 -1
package/crank.cjs
CHANGED
|
@@ -168,6 +168,7 @@ const IsInForOfLoop = 1 << 13;
|
|
|
168
168
|
const IsInForAwaitOfLoop = 1 << 14;
|
|
169
169
|
const NeedsToYield = 1 << 15;
|
|
170
170
|
const PropsAvailable = 1 << 16;
|
|
171
|
+
const IsSchedulingRefresh = 1 << 17;
|
|
171
172
|
function getFlag(ret, flag) {
|
|
172
173
|
return !!(ret.f & flag);
|
|
173
174
|
}
|
|
@@ -521,10 +522,10 @@ function diffChildren(adapter, root, host, ctx, scope, parent, newChildren) {
|
|
|
521
522
|
}
|
|
522
523
|
}
|
|
523
524
|
else if (ret) {
|
|
525
|
+
let candidateFound = false;
|
|
524
526
|
// we do not need to add the retainer to the graveyard if it is the
|
|
525
527
|
// fallback of another retainer
|
|
526
528
|
// search for the tag in fallback chain
|
|
527
|
-
let candidateFound = false;
|
|
528
529
|
for (let predecessor = ret, candidate = ret.fallback; candidate; predecessor = candidate, candidate = candidate.fallback) {
|
|
529
530
|
if (candidate.el.tag === child.tag) {
|
|
530
531
|
// If we find a retainer in the fallback chain with the same tag,
|
|
@@ -1359,6 +1360,9 @@ class Context extends eventTarget.CustomEventTarget {
|
|
|
1359
1360
|
});
|
|
1360
1361
|
}
|
|
1361
1362
|
}
|
|
1363
|
+
if (getFlag(ctx.ret, IsScheduling)) {
|
|
1364
|
+
setFlag(ctx.ret, IsSchedulingRefresh);
|
|
1365
|
+
}
|
|
1362
1366
|
let diff;
|
|
1363
1367
|
const schedulePromises = [];
|
|
1364
1368
|
try {
|
|
@@ -1704,10 +1708,11 @@ function runComponent(ctx) {
|
|
|
1704
1708
|
if (getFlag(ctx.ret, IsInForOfLoop) &&
|
|
1705
1709
|
!getFlag(ctx.ret, NeedsToYield) &&
|
|
1706
1710
|
!getFlag(ctx.ret, IsUnmounted) &&
|
|
1707
|
-
!getFlag(ctx.ret,
|
|
1711
|
+
!getFlag(ctx.ret, IsSchedulingRefresh)) {
|
|
1708
1712
|
console.error(`Component <${getTagName(ctx.ret.el.tag)}> yielded/returned more than once in for...of loop`);
|
|
1709
1713
|
}
|
|
1710
1714
|
setFlag(ctx.ret, NeedsToYield, false);
|
|
1715
|
+
setFlag(ctx.ret, IsSchedulingRefresh, false);
|
|
1711
1716
|
if (iteration.done) {
|
|
1712
1717
|
setFlag(ctx.ret, IsSyncGen, false);
|
|
1713
1718
|
ctx.iterator = undefined;
|
|
@@ -1753,11 +1758,12 @@ function runComponent(ctx) {
|
|
|
1753
1758
|
if (getFlag(ctx.ret, IsInForOfLoop) &&
|
|
1754
1759
|
!getFlag(ctx.ret, NeedsToYield) &&
|
|
1755
1760
|
!getFlag(ctx.ret, IsUnmounted) &&
|
|
1756
|
-
!getFlag(ctx.ret,
|
|
1761
|
+
!getFlag(ctx.ret, IsSchedulingRefresh)) {
|
|
1757
1762
|
console.error(`Component <${getTagName(ctx.ret.el.tag)}> yielded/returned more than once in for...of loop`);
|
|
1758
1763
|
}
|
|
1759
1764
|
}
|
|
1760
1765
|
setFlag(ctx.ret, NeedsToYield, false);
|
|
1766
|
+
setFlag(ctx.ret, IsSchedulingRefresh, false);
|
|
1761
1767
|
if (iteration.done) {
|
|
1762
1768
|
setFlag(ctx.ret, IsAsyncGen, false);
|
|
1763
1769
|
ctx.iterator = undefined;
|
|
@@ -1989,18 +1995,17 @@ function commitComponent(ctx, schedulePromises, hydrationNodes) {
|
|
|
1989
1995
|
});
|
|
1990
1996
|
return getValue(ctx.ret);
|
|
1991
1997
|
}
|
|
1992
|
-
const wasScheduling = getFlag(ctx.ret, IsScheduling);
|
|
1993
1998
|
const values = commitChildren(ctx.adapter, ctx.host, ctx, ctx.scope, ctx.ret, ctx.index, schedulePromises, hydrationNodes);
|
|
1994
1999
|
if (getFlag(ctx.ret, IsUnmounted)) {
|
|
1995
2000
|
return;
|
|
1996
2001
|
}
|
|
1997
2002
|
eventTarget.addEventTargetDelegates(ctx.ctx, values);
|
|
1998
2003
|
// Execute schedule callbacks early to check for async deferral
|
|
1999
|
-
const
|
|
2004
|
+
const wasScheduling = getFlag(ctx.ret, IsScheduling);
|
|
2000
2005
|
let schedulePromises1;
|
|
2006
|
+
const callbacks = scheduleMap.get(ctx);
|
|
2001
2007
|
if (callbacks) {
|
|
2002
2008
|
scheduleMap.delete(ctx);
|
|
2003
|
-
// TODO: think about error handling for schedule callbacks
|
|
2004
2009
|
setFlag(ctx.ret, IsScheduling);
|
|
2005
2010
|
const result = ctx.adapter.read(_utils.unwrap(values));
|
|
2006
2011
|
for (const callback of callbacks) {
|
|
@@ -2011,7 +2016,7 @@ function commitComponent(ctx, schedulePromises, hydrationNodes) {
|
|
|
2011
2016
|
}
|
|
2012
2017
|
if (schedulePromises1 && !getFlag(ctx.ret, DidCommit)) {
|
|
2013
2018
|
const scheduleCallbacksP = Promise.all(schedulePromises1).then(() => {
|
|
2014
|
-
setFlag(ctx.ret, IsScheduling,
|
|
2019
|
+
setFlag(ctx.ret, IsScheduling, wasScheduling);
|
|
2015
2020
|
propagateComponent(ctx);
|
|
2016
2021
|
if (ctx.ret.fallback) {
|
|
2017
2022
|
unmount(ctx.adapter, ctx.host, ctx.parent, ctx.ret.fallback, false);
|
|
@@ -2051,6 +2056,37 @@ function commitComponent(ctx, schedulePromises, hydrationNodes) {
|
|
|
2051
2056
|
// if schedule callbacks call refresh() or async mounting is happening.
|
|
2052
2057
|
return getValue(ctx.ret, true);
|
|
2053
2058
|
}
|
|
2059
|
+
/**
|
|
2060
|
+
* Checks if a target retainer is active (contributing) in the host's retainer tree.
|
|
2061
|
+
* Performs a downward traversal from host to find if target is in the active path.
|
|
2062
|
+
*/
|
|
2063
|
+
function isRetainerActive(target, host) {
|
|
2064
|
+
const stack = [host];
|
|
2065
|
+
while (stack.length > 0) {
|
|
2066
|
+
const current = stack.pop();
|
|
2067
|
+
if (current === target) {
|
|
2068
|
+
return true;
|
|
2069
|
+
}
|
|
2070
|
+
// Add direct children to stack (skip if this is a host boundary)
|
|
2071
|
+
// Host boundaries are: DOM elements (string tags) or Portal, but NOT Fragment
|
|
2072
|
+
const isHostBoundary = current !== host &&
|
|
2073
|
+
((typeof current.el.tag === "string" && current.el.tag !== Fragment) ||
|
|
2074
|
+
current.el.tag === Portal);
|
|
2075
|
+
if (current.children && !isHostBoundary) {
|
|
2076
|
+
const children = _utils.wrap(current.children);
|
|
2077
|
+
for (const child of children) {
|
|
2078
|
+
if (child) {
|
|
2079
|
+
stack.push(child);
|
|
2080
|
+
}
|
|
2081
|
+
}
|
|
2082
|
+
}
|
|
2083
|
+
// Add fallback chains (only if current retainer is using fallback)
|
|
2084
|
+
if (current.fallback && !getFlag(current, DidDiff)) {
|
|
2085
|
+
stack.push(current.fallback);
|
|
2086
|
+
}
|
|
2087
|
+
}
|
|
2088
|
+
return false;
|
|
2089
|
+
}
|
|
2054
2090
|
/**
|
|
2055
2091
|
* Propagates component changes up to ancestors when rendering starts from a
|
|
2056
2092
|
* component via refresh() or multiple for await...of renders. This handles
|
|
@@ -2061,14 +2097,20 @@ function propagateComponent(ctx) {
|
|
|
2061
2097
|
const values = getChildValues(ctx.ret, ctx.index);
|
|
2062
2098
|
eventTarget.addEventTargetDelegates(ctx.ctx, values, (ctx1) => ctx1[_ContextState].host === ctx.host);
|
|
2063
2099
|
const host = ctx.host;
|
|
2100
|
+
const initiator = ctx.ret;
|
|
2101
|
+
// Check if initiator is active in the host's tree
|
|
2102
|
+
if (!isRetainerActive(initiator, host)) {
|
|
2103
|
+
return;
|
|
2104
|
+
}
|
|
2064
2105
|
const props = stripSpecialProps(host.el.props);
|
|
2106
|
+
const hostChildren = getChildValues(host, 0);
|
|
2065
2107
|
ctx.adapter.arrange({
|
|
2066
2108
|
tag: host.el.tag,
|
|
2067
2109
|
tagName: getTagName(host.el.tag),
|
|
2068
2110
|
node: host.value,
|
|
2069
2111
|
props,
|
|
2070
2112
|
oldProps: props,
|
|
2071
|
-
children:
|
|
2113
|
+
children: hostChildren,
|
|
2072
2114
|
});
|
|
2073
2115
|
flush(ctx.adapter, ctx.root, ctx);
|
|
2074
2116
|
}
|