@swiftbrowser/web 0.10.3 → 0.10.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swiftbrowser/web",
3
- "version": "0.10.3",
3
+ "version": "0.10.4",
4
4
  "type": "module",
5
5
  "description": "SwiftBrowser web renderer and dev server: applies render ops from a Swift/Wasm app to the DOM inside an iPhone frame.",
6
6
  "repository": {
package/src/animation.ts CHANGED
@@ -961,12 +961,36 @@ export class Animator {
961
961
  el.animate([from, to], { ...timing, fill: 'backwards' });
962
962
  }
963
963
 
964
+ /** The exit clones playing, each with the element it left (its parent at removal): `dropExitClonesIn`. */
965
+ private readonly exitClones = new Map<HTMLElement, HTMLElement>();
966
+
967
+ /**
968
+ * Drops the exit clones of elements that left `container` or anything in
969
+ * it: a clone stands in for content of a container that is now going
970
+ * itself, and would play on over whatever takes the container's place. A
971
+ * screen that swaps its content for a placeholder a commit before it is
972
+ * popped (a split view's detail as its selection clears) left its bar
973
+ * group's clone fading over the uncovered screen's bar. (A clone not built
974
+ * yet, its pass still waiting for the frame, is refused in `exit`.)
975
+ */
976
+ dropExitClonesIn(container: HTMLElement): void {
977
+ for (const [clone, owner] of this.exitClones) {
978
+ if (owner !== container && !container.contains(owner)) continue;
979
+ this.exitClones.delete(clone);
980
+ for (const animation of clone.getAnimations()) animation.cancel();
981
+ clone.remove();
982
+ }
983
+ }
984
+
964
985
  /**
965
986
  * Re-insert a visual clone of a removed element at its old position and
966
987
  * play its transition backwards; the clone is dropped when done.
967
988
  */
968
989
  exit(rec: RemovedRecord, animation: Animation | undefined): HTMLElement | null {
969
990
  const parent = rec.ancestors[0] ?? null;
991
+ // The element it left has gone itself since (a later pass in the same
992
+ // task popped the screen): nothing is left to leave from.
993
+ if (parent && !parent.isConnected) return null;
970
994
  const end = transitionStart(rec.transition ?? implicitTransitionOf(rec.el, parent), true);
971
995
  if (isIdentity(end) || !rec.rect) return null;
972
996
  const clone = ghostClone(rec.el);
@@ -999,7 +1023,11 @@ export class Animator {
999
1023
  }
1000
1024
  const timing = baseTiming(timingFor(animation));
1001
1025
  const anim = clone.animate([from, to], { ...timing, fill: 'forwards' });
1002
- const done = (): void => clone.remove();
1026
+ if (parent) this.exitClones.set(clone, parent);
1027
+ const done = (): void => {
1028
+ this.exitClones.delete(clone);
1029
+ clone.remove();
1030
+ };
1003
1031
  anim.finished.then(done, done);
1004
1032
  window.setTimeout(done, timing.duration + timing.delay + 100);
1005
1033
  return clone;
package/src/renderer.ts CHANGED
@@ -2231,6 +2231,8 @@ export class Renderer {
2231
2231
  const el = this.elements.get(id);
2232
2232
  if (!el) throw new RendererError(`Cannot remove unknown element ${id}`, op);
2233
2233
  const parent = el.parentElement;
2234
+ // Clones of what left this subtree earlier (a bar group's, src/animation.ts) go with it.
2235
+ this.animator.dropExitClonesIn(el);
2234
2236
  const stack = parent?.classList.contains('sb-navstack-screens')
2235
2237
  ? parent.parentElement
2236
2238
  : null;