@b9g/crank 0.7.4 → 0.7.6

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/crank.js CHANGED
@@ -248,9 +248,15 @@ function getValue(ret, isNested = false, index) {
248
248
  function getChildValues(ret, startIndex) {
249
249
  const values = [];
250
250
  const lingerers = ret.lingerers;
251
- const children = wrap(ret.children);
251
+ const rawChildren = ret.children;
252
+ const isChildrenArray = Array.isArray(rawChildren);
253
+ const childrenLength = rawChildren === undefined
254
+ ? 0
255
+ : isChildrenArray
256
+ ? rawChildren.length
257
+ : 1;
252
258
  let currentIndex = startIndex;
253
- for (let i = 0; i < children.length; i++) {
259
+ for (let i = 0; i < childrenLength; i++) {
254
260
  if (lingerers != null && lingerers[i] != null) {
255
261
  const rets = lingerers[i];
256
262
  for (const ret of rets) {
@@ -271,7 +277,9 @@ function getChildValues(ret, startIndex) {
271
277
  }
272
278
  }
273
279
  }
274
- const child = children[i];
280
+ const child = isChildrenArray
281
+ ? rawChildren[i]
282
+ : rawChildren;
275
283
  if (child) {
276
284
  const value = getValue(child, true, currentIndex);
277
285
  if (Array.isArray(value)) {
@@ -290,8 +298,8 @@ function getChildValues(ret, startIndex) {
290
298
  }
291
299
  }
292
300
  }
293
- if (lingerers != null && lingerers.length > children.length) {
294
- for (let i = children.length; i < lingerers.length; i++) {
301
+ if (lingerers != null && lingerers.length > childrenLength) {
302
+ for (let i = childrenLength; i < lingerers.length; i++) {
295
303
  const rets = lingerers[i];
296
304
  if (rets != null) {
297
305
  for (const ret of rets) {
@@ -450,7 +458,155 @@ function renderRoot(adapter, root, ret, children) {
450
458
  }
451
459
  return adapter.read(unwrap(getChildValues(ret)));
452
460
  }
461
+ function diffChild(adapter, root, host, ctx, scope, parent, newChildren) {
462
+ let child = narrow(newChildren);
463
+ let ret = parent.children;
464
+ let graveyard;
465
+ let diff;
466
+ if (typeof child === "object") {
467
+ let childCopied = false;
468
+ // Check key match
469
+ const oldKey = typeof ret === "object" ? ret.el.props.key : undefined;
470
+ const newKey = child.props.key;
471
+ if (oldKey !== newKey) {
472
+ if (typeof ret === "object") {
473
+ (graveyard = graveyard || []).push(ret);
474
+ }
475
+ ret = undefined;
476
+ }
477
+ if (child.tag === Copy) {
478
+ childCopied = true;
479
+ }
480
+ else if (typeof ret === "object" &&
481
+ ret.el === child &&
482
+ getFlag(ret, DidCommit)) {
483
+ childCopied = true;
484
+ }
485
+ else {
486
+ if (ret && ret.el.tag === child.tag) {
487
+ ret.el = child;
488
+ if (child.props.copy && typeof child.props.copy !== "string") {
489
+ childCopied = true;
490
+ }
491
+ }
492
+ else if (ret) {
493
+ let candidateFound = false;
494
+ for (let predecessor = ret, candidate = ret.fallback; candidate; predecessor = candidate, candidate = candidate.fallback) {
495
+ if (candidate.el.tag === child.tag) {
496
+ const clone = cloneRetainer(candidate);
497
+ setFlag(clone, IsResurrecting);
498
+ predecessor.fallback = clone;
499
+ const fallback = ret;
500
+ ret = candidate;
501
+ ret.el = child;
502
+ ret.fallback = fallback;
503
+ setFlag(ret, DidDiff, false);
504
+ candidateFound = true;
505
+ break;
506
+ }
507
+ }
508
+ if (!candidateFound) {
509
+ const fallback = ret;
510
+ ret = new Retainer(child);
511
+ ret.fallback = fallback;
512
+ }
513
+ }
514
+ else {
515
+ ret = new Retainer(child);
516
+ }
517
+ if (childCopied && getFlag(ret, DidCommit)) ;
518
+ else if (child.tag === Raw || child.tag === Text) ;
519
+ else if (child.tag === Fragment) {
520
+ diff = diffChildren(adapter, root, host, ctx, scope, ret, ret.el.props.children);
521
+ }
522
+ else if (typeof child.tag === "function") {
523
+ diff = diffComponent(adapter, root, host, ctx, scope, ret);
524
+ }
525
+ else {
526
+ diff = diffHost(adapter, root, ctx, scope, ret);
527
+ }
528
+ }
529
+ if (typeof ret === "object") {
530
+ if (childCopied) {
531
+ setFlag(ret, IsCopied);
532
+ diff = getInflightDiff(ret);
533
+ }
534
+ else {
535
+ setFlag(ret, IsCopied, false);
536
+ }
537
+ }
538
+ }
539
+ else if (typeof child === "string") {
540
+ if (typeof ret === "object" && ret.el.tag === Text) {
541
+ ret.el.props.value = child;
542
+ }
543
+ else {
544
+ if (typeof ret === "object") {
545
+ (graveyard = graveyard || []).push(ret);
546
+ }
547
+ ret = new Retainer(createElement(Text, { value: child }));
548
+ }
549
+ }
550
+ else {
551
+ if (typeof ret === "object") {
552
+ (graveyard = graveyard || []).push(ret);
553
+ }
554
+ ret = undefined;
555
+ }
556
+ parent.children = ret;
557
+ if (isPromiseLike(diff)) {
558
+ const diff1 = diff.finally(() => {
559
+ setFlag(parent, DidDiff);
560
+ if (graveyard) {
561
+ if (parent.graveyard) {
562
+ for (let i = 0; i < graveyard.length; i++) {
563
+ parent.graveyard.push(graveyard[i]);
564
+ }
565
+ }
566
+ else {
567
+ parent.graveyard = graveyard;
568
+ }
569
+ }
570
+ });
571
+ let onNextDiffs;
572
+ const diff2 = (parent.pendingDiff = safeRace([
573
+ diff1,
574
+ new Promise((resolve) => (onNextDiffs = resolve)),
575
+ ]));
576
+ if (parent.onNextDiff) {
577
+ parent.onNextDiff(diff2);
578
+ }
579
+ parent.onNextDiff = onNextDiffs;
580
+ return diff2;
581
+ }
582
+ else {
583
+ setFlag(parent, DidDiff);
584
+ if (graveyard) {
585
+ if (parent.graveyard) {
586
+ for (let i = 0; i < graveyard.length; i++) {
587
+ parent.graveyard.push(graveyard[i]);
588
+ }
589
+ }
590
+ else {
591
+ parent.graveyard = graveyard;
592
+ }
593
+ }
594
+ if (parent.onNextDiff) {
595
+ parent.onNextDiff(diff);
596
+ parent.onNextDiff = undefined;
597
+ }
598
+ parent.pendingDiff = undefined;
599
+ }
600
+ }
453
601
  function diffChildren(adapter, root, host, ctx, scope, parent, newChildren) {
602
+ // Fast path for the common single non-keyed child case
603
+ if (!Array.isArray(newChildren) &&
604
+ (typeof newChildren !== "object" ||
605
+ newChildren === null ||
606
+ typeof newChildren[Symbol.iterator] !== "function") &&
607
+ !Array.isArray(parent.children)) {
608
+ return diffChild(adapter, root, host, ctx, scope, parent, newChildren);
609
+ }
454
610
  const oldRetained = wrap(parent.children);
455
611
  const newRetained = [];
456
612
  const newChildren1 = arrayify(newChildren);
@@ -751,7 +907,7 @@ function commit(adapter, host, ret, ctx, scope, root, index, schedulePromises, h
751
907
  }
752
908
  }
753
909
  if (skippedHydrationNodes) {
754
- skippedHydrationNodes.splice(0, wrap(value).length);
910
+ skippedHydrationNodes.splice(0, value == null ? 0 : Array.isArray(value) ? value.length : 1);
755
911
  }
756
912
  if (!getFlag(ret, DidCommit)) {
757
913
  setFlag(ret, DidCommit);
@@ -766,8 +922,17 @@ function commit(adapter, host, ret, ctx, scope, root, index, schedulePromises, h
766
922
  }
767
923
  function commitChildren(adapter, host, ctx, scope, root, parent, index, schedulePromises, hydrationNodes) {
768
924
  let values = [];
769
- for (let i = 0, children = wrap(parent.children); i < children.length; i++) {
770
- let child = children[i];
925
+ const rawChildren = parent.children;
926
+ const isChildrenArray = Array.isArray(rawChildren);
927
+ const childrenLength = rawChildren === undefined
928
+ ? 0
929
+ : isChildrenArray
930
+ ? rawChildren.length
931
+ : 1;
932
+ for (let i = 0; i < childrenLength; i++) {
933
+ let child = isChildrenArray
934
+ ? rawChildren[i]
935
+ : rawChildren;
771
936
  let schedulePromises1;
772
937
  let isSchedulingFallback = false;
773
938
  while (child &&
@@ -1052,6 +1217,7 @@ function commitHost(adapter, ret, ctx, root, schedulePromises, hydrationNodes) {
1052
1217
  props,
1053
1218
  children,
1054
1219
  oldProps,
1220
+ scope,
1055
1221
  root,
1056
1222
  });
1057
1223
  }
@@ -1209,12 +1375,18 @@ function unmountChildren(adapter, host, ctx, root, ret, isNested) {
1209
1375
  }
1210
1376
  ret.graveyard = undefined;
1211
1377
  }
1212
- for (let i = 0, children = wrap(ret.children); i < children.length; i++) {
1213
- const child = children[i];
1214
- if (typeof child === "object") {
1215
- unmount(adapter, host, ctx, root, child, isNested);
1378
+ const rawChildren = ret.children;
1379
+ if (Array.isArray(rawChildren)) {
1380
+ for (let i = 0; i < rawChildren.length; i++) {
1381
+ const child = rawChildren[i];
1382
+ if (typeof child === "object") {
1383
+ unmount(adapter, host, ctx, root, child, isNested);
1384
+ }
1216
1385
  }
1217
1386
  }
1387
+ else if (rawChildren !== undefined) {
1388
+ unmount(adapter, host, ctx, root, rawChildren, isNested);
1389
+ }
1218
1390
  }
1219
1391
  const provisionMaps = new WeakMap();
1220
1392
  const scheduleMap = new WeakMap();
@@ -2084,12 +2256,16 @@ function isRetainerActive(target, host) {
2084
2256
  ((typeof current.el.tag === "string" && current.el.tag !== Fragment) ||
2085
2257
  current.el.tag === Portal);
2086
2258
  if (current.children && !isHostBoundary) {
2087
- const children = wrap(current.children);
2088
- for (const child of children) {
2089
- if (child) {
2090
- stack.push(child);
2259
+ if (Array.isArray(current.children)) {
2260
+ for (const child of current.children) {
2261
+ if (child) {
2262
+ stack.push(child);
2263
+ }
2091
2264
  }
2092
2265
  }
2266
+ else {
2267
+ stack.push(current.children);
2268
+ }
2093
2269
  }
2094
2270
  // Add fallback chains (only if current retainer is using fallback)
2095
2271
  if (current.fallback && !getFlag(current, DidDiff)) {
@@ -2113,6 +2289,11 @@ function propagateComponent(ctx) {
2113
2289
  if (!isRetainerActive(initiator, host)) {
2114
2290
  return;
2115
2291
  }
2292
+ // Check if host has been committed (has a node)
2293
+ // Fixes #334: refresh() called before component yields
2294
+ if (!getFlag(host, DidCommit)) {
2295
+ return;
2296
+ }
2116
2297
  const props = stripSpecialProps(host.el.props);
2117
2298
  const hostChildren = getChildValues(host, 0);
2118
2299
  ctx.adapter.arrange({
@@ -2122,6 +2303,7 @@ function propagateComponent(ctx) {
2122
2303
  props,
2123
2304
  oldProps: props,
2124
2305
  children: hostChildren,
2306
+ scope: host.scope,
2125
2307
  root: ctx.root,
2126
2308
  });
2127
2309
  flush(ctx.adapter, ctx.root, ctx);