Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | 37x 37x 37x 37x 37x 37x 37x 37x 37x 37x | import { addUniqueItem, removeItem } from "../../utils/array" import { IProjectionNode } from "../node/types" export class NodeStack { lead?: IProjectionNode prevLead?: IProjectionNode members: IProjectionNode[] = [] add(node: IProjectionNode) { addUniqueItem(this.members, node) node.scheduleRender() } remove(node: IProjectionNode) { removeItem(this.members, node) if (node === this.prevLead) { this.prevLead = undefined } if (node === this.lead) { const prevLead = this.members[this.members.length - 1] if (prevLead) { this.promote(prevLead) } } } relegate(node: IProjectionNode): boolean { const indexOfNode = this.members.findIndex((member) => node === member) if (indexOfNode === 0) return false /** * Find the next projection node that is present */ let prevLead: IProjectionNode | undefined for (let i = indexOfNode; i >= 0; i--) { const member = this.members[i] if (member.isPresent !== false) { prevLead = member break } } if (prevLead) { this.promote(prevLead) return true } else { return false } } promote(node: IProjectionNode, preserveFollowOpacity?: boolean) { const prevLead = this.lead if (node === prevLead) return this.prevLead = prevLead this.lead = node node.show() if (prevLead) { prevLead.instance && prevLead.scheduleRender() node.scheduleRender() node.resumeFrom = prevLead if (preserveFollowOpacity) { node.resumeFrom.preserveOpacity = true } if (prevLead.snapshot) { node.snapshot = prevLead.snapshot node.snapshot.latestValues = prevLead.animationValues || prevLead.latestValues node.snapshot.isShared = true } if (node.root?.isUpdating) { node.isLayoutDirty = true } const { crossfade } = node.options if (crossfade === false) { prevLead.hide() } else { } /** * TODO: * - Test border radius when previous node was deleted * - boxShadow mixing * - Shared between element A in scrolled container and element B (scroll stays the same or changes) * - Shared between element A in transformed container and element B (transform stays the same or changes) * - Shared between element A in scrolled page and element B (scroll stays the same or changes) * --- * - Crossfade opacity of root nodes * - layoutId changes after animation * - layoutId changes mid animation */ } } exitAnimationComplete() { this.members.forEach((node) => { node.options.onExitComplete?.() node.resumingFrom?.options.onExitComplete?.() }) } scheduleRender() { this.members.forEach((node) => { node.instance && node.scheduleRender(false) }) } /** * Clear any leads that have been removed this render to prevent them from being * used in future animations and to prevent memory leaks */ removeLeadSnapshot() { if (this.lead && this.lead.snapshot) { this.lead.snapshot = undefined } } } |