Fix sourceViewTag resolution timing for sheet transitions

findNodeHandle(ref.current) at render time returns undefined on the
first render since the ref isn't populated yet. Fix this by:

- Menu.Outer: use useEffect to resolve the tag after mount when the
  trigger ref is already populated
- LabelsBtn/ThreadgateBtn: use callback refs to capture the node
  handle in state immediately when the button mounts

https://claude.ai/code/session_011cNDhEb2cDgg5QbVuzEyH1
This commit is contained in:
Claude
2026-02-28 21:05:20 +00:00
committed by Samuel Newman
parent ce397db233
commit 382710f93e
3 changed files with 36 additions and 10 deletions
+17 -4
View File
@@ -1,4 +1,12 @@
import {cloneElement, Fragment, isValidElement, useMemo, useRef} from 'react'
import {
cloneElement,
Fragment,
isValidElement,
useEffect,
useMemo,
useRef,
useState,
} from 'react'
import {
findNodeHandle,
Pressable,
@@ -106,9 +114,14 @@ export function Outer({
}>) {
const context = useMenuContext()
const {_} = useLingui()
const sourceViewTag = enableTransition
? (findNodeHandle(context.triggerRef.current) ?? undefined)
: undefined
const [sourceViewTag, setSourceViewTag] = useState<number>()
useEffect(() => {
if (enableTransition && context.triggerRef.current) {
const tag = findNodeHandle(context.triggerRef.current)
if (tag != null) setSourceViewTag(tag)
}
}, [enableTransition, context.triggerRef])
return (
<Dialog.Outer
+10 -3
View File
@@ -1,4 +1,4 @@
import {useRef} from 'react'
import {useState} from 'react'
import {findNodeHandle, Keyboard, View} from 'react-native'
import {msg} from '@lingui/core/macro'
import {useLingui} from '@lingui/react'
@@ -30,7 +30,14 @@ export function LabelsBtn({
}) {
const control = Dialog.useDialogControl()
const {_} = useLingui()
const btnRef = useRef<View>(null)
const [sourceViewTag, setSourceViewTag] = useState<number>()
const btnRef = (node: View | null) => {
if (node) {
const tag = findNodeHandle(node)
if (tag != null) setSourceViewTag(tag)
}
}
const hasLabel = labels.length > 0
@@ -80,7 +87,7 @@ export function LabelsBtn({
control={control}
nativeOptions={{
preventExpansion: true,
sourceViewTag: findNodeHandle(btnRef.current) ?? undefined,
sourceViewTag,
}}>
<Dialog.Handle />
<DialogInner
@@ -1,4 +1,4 @@
import {useEffect, useMemo, useRef, useState} from 'react'
import {useEffect, useMemo, useState} from 'react'
import {
findNodeHandle,
Keyboard,
@@ -52,7 +52,13 @@ export function ThreadgateBtn({
const {_} = useLingui()
const ax = useAnalytics()
const control = Dialog.useDialogControl()
const btnRef = useRef<View>(null)
const [sourceViewTag, setSourceViewTag] = useState<number>()
const btnRef = (node: View | null) => {
if (node) {
const tag = findNodeHandle(node)
if (tag != null) setSourceViewTag(tag)
}
}
const [threadgateNudged, setThreadgateNudged] = useThreadgateNudged()
const [showTooltip, setShowTooltip] = useState(false)
const [tooltipWasShown] = useState(!threadgateNudged)
@@ -175,7 +181,7 @@ export function ThreadgateBtn({
<PostInteractionSettingsControlledDialog
control={control}
sourceViewTag={findNodeHandle(btnRef.current) ?? undefined}
sourceViewTag={sourceViewTag}
onSave={() => {
if (persist) {
persistChanges({