sortNodePosition throws when a sibling in enteringChildren has not mounted yet (Firefox: compareDocumentPosition: Argument 1 is not an object)
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 1/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 88/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- typescript
- Domain
- frontend
Research direction
Start in packages/motion-dom/src/render/VisualElement.ts at sortNodePosition, then review the unit-level reproduction with two HTMLVisualElements where only one is mounted. Add coverage for sorting a mounted element against an unmounted sibling and confirm the comparator returns safely without throwing; the existing mounted behavior should remain unchanged.
Written by the indexing model from the issue text.
Description
Summary
VisualElement.sortNodePosition guards this.current but not other.current. When a child that mounts after its parent computes its stagger delay, calcChildStagger sorts parent.enteringChildren by DOM position; siblings that are registered but not mounted yet have current === null, and a.compareDocumentPosition(null) throws:
TypeError: Node.compareDocumentPosition: Argument 1 is not an object. (Firefox)
Every child whose animateChanges throws never runs its initial → animate transition and stays at its initial values. In a Nuxt app the throw happens in a mounted hook during hydration and turns into the app's error page.
Why it only shows in Firefox
It depends on the argument order of Array.prototype.sort's comparator. SpiderMonkey's merge sort calls compare(earlier, later), so the already-mounted element is this and the unmounted sibling is other — the unguarded side. V8's insertion sort calls compare(pivot, existing) with the later (still unmounted) element as this, which hits the existing !this.current guard and returns 0. Same data, same code, different comparator order — which is why motiondivision/motion-vue#208 could not be reproduced in Chrome.
Where the unmounted siblings come from
motion-vue registers a child with its parent when the VisualElement is created, before it has mounted (motion-state.ts#L228), and animation-state.ts then calls calcChildStagger(parent.enteringChildren, …) for children mounting after the parent (animation-state.ts#L402-L405). The sort in motion-dom should not depend on every entry having an element, though — the guard for this.current already acknowledges that.
Code: packages/motion-dom/src/render/VisualElement.ts#L609-L621
Reproduction
Standalone page (motion-v 2.4.4 / motion-dom 13.4.4, Vue 3.5.43), full analysis and results in https://github.com/motiondivision/motion-vue/issues/208#issuecomment-5831915170. Open it in Firefox: 3 errors and 4 of 5 cards stuck at opacity: 0; Chromium: no errors.
At the unit level: two HTMLVisualElements, mount only one, mounted.sortNodePosition(unmounted) throws instead of returning 0.
Fix
Add !other.current || to the guard in sortNodePosition. PR follows.
- Dominant language
- TypeScript
- Stars
- 34k
- Forks
- 1.4k
- Avg merge
- 23h 13m
- Merged PRs (30d)
- 90
Getting set up
Starts the project's dev container in your browser, under your own GitHub account.
- No Dockerfile or Docker Compose file
- No pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from motiondivision/motion
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 66/100
motiondivision/motion#3945 · 3 comments ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
motiondivision/motion#3935 ·
Maintainers usually reply within 1 day
-
Difficulty 3/5 1-2 days Newbie friendliness 78/100
motiondivision/motion#3944 ·
Maintainers usually reply within 1 day
-
Difficulty 3/5 1-2 days Newbie friendliness 45/100
motiondivision/motion#3942 ·
Maintainers usually reply within 1 day
-
[FEATURE] AnimateSuspense for transitions between suspense fallbacks and streamed contentMay be free again A pull request for this issue was closed without being merged. Openfeature
Difficulty 5/5 Over a week Newbie friendliness 35/100
motiondivision/motion#3173 · 9 reactions ·
Maintainers usually reply within 1 day
All issues in motiondivision/motion
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 1 day
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
jbacalso24/mimry#459 · 1 comment ·
Maintainers usually reply within 1 day
-
architecture help wanted hive/claimed-by-architect origin/architect stage/030-pr-in-progress tech-debt
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
kubestellar/console#24422 · 1 comment ·
Maintainers usually reply within 1 day
-
area: backends type: docs
Difficulty 1/5 1-3 hours Newbie friendliness 83/100
schlessera/brain-kit#2383 ·
Maintainers usually reply within 1 day
-
agent duplicate providers tool triaged
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
Maintainers usually reply within 1 day