@b9g/crank 0.7.1 → 0.7.3
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 +540 -84
- package/_css.js.map +1 -1
- package/_utils.js.map +1 -1
- 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/dom.cjs +16 -1
- package/dom.cjs.map +1 -1
- package/dom.js +16 -1
- package/dom.js.map +1 -1
- package/package.json +2 -1
- package/umd.js +66 -9
- package/umd.js.map +1 -1
package/crank.js
CHANGED
|
@@ -165,6 +165,7 @@ const IsInForOfLoop = 1 << 13;
|
|
|
165
165
|
const IsInForAwaitOfLoop = 1 << 14;
|
|
166
166
|
const NeedsToYield = 1 << 15;
|
|
167
167
|
const PropsAvailable = 1 << 16;
|
|
168
|
+
const IsSchedulingRefresh = 1 << 17;
|
|
168
169
|
function getFlag(ret, flag) {
|
|
169
170
|
return !!(ret.f & flag);
|
|
170
171
|
}
|
|
@@ -518,10 +519,10 @@ function diffChildren(adapter, root, host, ctx, scope, parent, newChildren) {
|
|
|
518
519
|
}
|
|
519
520
|
}
|
|
520
521
|
else if (ret) {
|
|
522
|
+
let candidateFound = false;
|
|
521
523
|
// we do not need to add the retainer to the graveyard if it is the
|
|
522
524
|
// fallback of another retainer
|
|
523
525
|
// search for the tag in fallback chain
|
|
524
|
-
let candidateFound = false;
|
|
525
526
|
for (let predecessor = ret, candidate = ret.fallback; candidate; predecessor = candidate, candidate = candidate.fallback) {
|
|
526
527
|
if (candidate.el.tag === child.tag) {
|
|
527
528
|
// If we find a retainer in the fallback chain with the same tag,
|
|
@@ -1356,6 +1357,9 @@ class Context extends CustomEventTarget {
|
|
|
1356
1357
|
});
|
|
1357
1358
|
}
|
|
1358
1359
|
}
|
|
1360
|
+
if (getFlag(ctx.ret, IsScheduling)) {
|
|
1361
|
+
setFlag(ctx.ret, IsSchedulingRefresh);
|
|
1362
|
+
}
|
|
1359
1363
|
let diff;
|
|
1360
1364
|
const schedulePromises = [];
|
|
1361
1365
|
try {
|
|
@@ -1701,10 +1705,11 @@ function runComponent(ctx) {
|
|
|
1701
1705
|
if (getFlag(ctx.ret, IsInForOfLoop) &&
|
|
1702
1706
|
!getFlag(ctx.ret, NeedsToYield) &&
|
|
1703
1707
|
!getFlag(ctx.ret, IsUnmounted) &&
|
|
1704
|
-
!getFlag(ctx.ret,
|
|
1708
|
+
!getFlag(ctx.ret, IsSchedulingRefresh)) {
|
|
1705
1709
|
console.error(`Component <${getTagName(ctx.ret.el.tag)}> yielded/returned more than once in for...of loop`);
|
|
1706
1710
|
}
|
|
1707
1711
|
setFlag(ctx.ret, NeedsToYield, false);
|
|
1712
|
+
setFlag(ctx.ret, IsSchedulingRefresh, false);
|
|
1708
1713
|
if (iteration.done) {
|
|
1709
1714
|
setFlag(ctx.ret, IsSyncGen, false);
|
|
1710
1715
|
ctx.iterator = undefined;
|
|
@@ -1750,11 +1755,12 @@ function runComponent(ctx) {
|
|
|
1750
1755
|
if (getFlag(ctx.ret, IsInForOfLoop) &&
|
|
1751
1756
|
!getFlag(ctx.ret, NeedsToYield) &&
|
|
1752
1757
|
!getFlag(ctx.ret, IsUnmounted) &&
|
|
1753
|
-
!getFlag(ctx.ret,
|
|
1758
|
+
!getFlag(ctx.ret, IsSchedulingRefresh)) {
|
|
1754
1759
|
console.error(`Component <${getTagName(ctx.ret.el.tag)}> yielded/returned more than once in for...of loop`);
|
|
1755
1760
|
}
|
|
1756
1761
|
}
|
|
1757
1762
|
setFlag(ctx.ret, NeedsToYield, false);
|
|
1763
|
+
setFlag(ctx.ret, IsSchedulingRefresh, false);
|
|
1758
1764
|
if (iteration.done) {
|
|
1759
1765
|
setFlag(ctx.ret, IsAsyncGen, false);
|
|
1760
1766
|
ctx.iterator = undefined;
|
|
@@ -1986,18 +1992,17 @@ function commitComponent(ctx, schedulePromises, hydrationNodes) {
|
|
|
1986
1992
|
});
|
|
1987
1993
|
return getValue(ctx.ret);
|
|
1988
1994
|
}
|
|
1989
|
-
const wasScheduling = getFlag(ctx.ret, IsScheduling);
|
|
1990
1995
|
const values = commitChildren(ctx.adapter, ctx.host, ctx, ctx.scope, ctx.ret, ctx.index, schedulePromises, hydrationNodes);
|
|
1991
1996
|
if (getFlag(ctx.ret, IsUnmounted)) {
|
|
1992
1997
|
return;
|
|
1993
1998
|
}
|
|
1994
1999
|
addEventTargetDelegates(ctx.ctx, values);
|
|
1995
2000
|
// Execute schedule callbacks early to check for async deferral
|
|
1996
|
-
const
|
|
2001
|
+
const wasScheduling = getFlag(ctx.ret, IsScheduling);
|
|
1997
2002
|
let schedulePromises1;
|
|
2003
|
+
const callbacks = scheduleMap.get(ctx);
|
|
1998
2004
|
if (callbacks) {
|
|
1999
2005
|
scheduleMap.delete(ctx);
|
|
2000
|
-
// TODO: think about error handling for schedule callbacks
|
|
2001
2006
|
setFlag(ctx.ret, IsScheduling);
|
|
2002
2007
|
const result = ctx.adapter.read(unwrap(values));
|
|
2003
2008
|
for (const callback of callbacks) {
|
|
@@ -2008,7 +2013,7 @@ function commitComponent(ctx, schedulePromises, hydrationNodes) {
|
|
|
2008
2013
|
}
|
|
2009
2014
|
if (schedulePromises1 && !getFlag(ctx.ret, DidCommit)) {
|
|
2010
2015
|
const scheduleCallbacksP = Promise.all(schedulePromises1).then(() => {
|
|
2011
|
-
setFlag(ctx.ret, IsScheduling,
|
|
2016
|
+
setFlag(ctx.ret, IsScheduling, wasScheduling);
|
|
2012
2017
|
propagateComponent(ctx);
|
|
2013
2018
|
if (ctx.ret.fallback) {
|
|
2014
2019
|
unmount(ctx.adapter, ctx.host, ctx.parent, ctx.ret.fallback, false);
|
|
@@ -2048,6 +2053,37 @@ function commitComponent(ctx, schedulePromises, hydrationNodes) {
|
|
|
2048
2053
|
// if schedule callbacks call refresh() or async mounting is happening.
|
|
2049
2054
|
return getValue(ctx.ret, true);
|
|
2050
2055
|
}
|
|
2056
|
+
/**
|
|
2057
|
+
* Checks if a target retainer is active (contributing) in the host's retainer tree.
|
|
2058
|
+
* Performs a downward traversal from host to find if target is in the active path.
|
|
2059
|
+
*/
|
|
2060
|
+
function isRetainerActive(target, host) {
|
|
2061
|
+
const stack = [host];
|
|
2062
|
+
while (stack.length > 0) {
|
|
2063
|
+
const current = stack.pop();
|
|
2064
|
+
if (current === target) {
|
|
2065
|
+
return true;
|
|
2066
|
+
}
|
|
2067
|
+
// Add direct children to stack (skip if this is a host boundary)
|
|
2068
|
+
// Host boundaries are: DOM elements (string tags) or Portal, but NOT Fragment
|
|
2069
|
+
const isHostBoundary = current !== host &&
|
|
2070
|
+
((typeof current.el.tag === "string" && current.el.tag !== Fragment) ||
|
|
2071
|
+
current.el.tag === Portal);
|
|
2072
|
+
if (current.children && !isHostBoundary) {
|
|
2073
|
+
const children = wrap(current.children);
|
|
2074
|
+
for (const child of children) {
|
|
2075
|
+
if (child) {
|
|
2076
|
+
stack.push(child);
|
|
2077
|
+
}
|
|
2078
|
+
}
|
|
2079
|
+
}
|
|
2080
|
+
// Add fallback chains (only if current retainer is using fallback)
|
|
2081
|
+
if (current.fallback && !getFlag(current, DidDiff)) {
|
|
2082
|
+
stack.push(current.fallback);
|
|
2083
|
+
}
|
|
2084
|
+
}
|
|
2085
|
+
return false;
|
|
2086
|
+
}
|
|
2051
2087
|
/**
|
|
2052
2088
|
* Propagates component changes up to ancestors when rendering starts from a
|
|
2053
2089
|
* component via refresh() or multiple for await...of renders. This handles
|
|
@@ -2058,14 +2094,20 @@ function propagateComponent(ctx) {
|
|
|
2058
2094
|
const values = getChildValues(ctx.ret, ctx.index);
|
|
2059
2095
|
addEventTargetDelegates(ctx.ctx, values, (ctx1) => ctx1[_ContextState].host === ctx.host);
|
|
2060
2096
|
const host = ctx.host;
|
|
2097
|
+
const initiator = ctx.ret;
|
|
2098
|
+
// Check if initiator is active in the host's tree
|
|
2099
|
+
if (!isRetainerActive(initiator, host)) {
|
|
2100
|
+
return;
|
|
2101
|
+
}
|
|
2061
2102
|
const props = stripSpecialProps(host.el.props);
|
|
2103
|
+
const hostChildren = getChildValues(host, 0);
|
|
2062
2104
|
ctx.adapter.arrange({
|
|
2063
2105
|
tag: host.el.tag,
|
|
2064
2106
|
tagName: getTagName(host.el.tag),
|
|
2065
2107
|
node: host.value,
|
|
2066
2108
|
props,
|
|
2067
2109
|
oldProps: props,
|
|
2068
|
-
children:
|
|
2110
|
+
children: hostChildren,
|
|
2069
2111
|
});
|
|
2070
2112
|
flush(ctx.adapter, ctx.root, ctx);
|
|
2071
2113
|
}
|