[Threadgate] Tweak threadgate buttons (#9173)
* tweak in-post threadgate button * tweak composer threadgate button * reduce date length slightly * pressed styles * make date length depend on breakpoint * add chevron to label btn * add tiny chevron, special-case button icon width * [Threadgate] Add hint (#9350) * get tooltip working on web * add compatibility layer for working in iOS sheets * add timeout to profile tooltip now that it appears instantly * rm debug code * Update ThreadgateBtn.tsx Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com> * remeasure when keyboard changes --------- Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com> * fix types * [Threadgate] Refresh dialog (#9342) * wip new ui * update threadgate dialog with new designs * restore nobody option * relayout android sheet when ratio changes * fix ratio changing case in bottom sheet * timebox reached, use setTimeout * update panel styles * missing imports * extract out Panel * tweak layout animation * fix icon color * use same color mechamism for icon as text * restore the header * refreshed toggle styles (#9343) * [Threadgate] Persist settings (#9341) * add persist toggle to threadgate dialog * move state back down * sort out spacing * wire up query * @surfdude29 tweaks * use tiny chevron in WhoCanReply * wait for prefetch before opening * move Panel into the Toggle namespace * default -> pref * use medium date length * rm hover state from web selects, fix border radius * fix key issue in Selects --------- Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>
This commit is contained in:
@@ -12,9 +12,11 @@ import {useWindowDimensions, View} from 'react-native'
|
||||
import Animated, {Easing, ZoomIn} from 'react-native-reanimated'
|
||||
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
||||
|
||||
import {useIsKeyboardVisible} from '#/lib/hooks/useIsKeyboardVisible'
|
||||
import {GlobalGestureEventsProvider} from '#/state/global-gesture-events'
|
||||
import {atoms as a, select, useTheme} from '#/alf'
|
||||
import {useOnGesture} from '#/components/hooks/useOnGesture'
|
||||
import {Portal} from '#/components/Portal'
|
||||
import {createPortalGroup, Portal as RootPortal} from '#/components/Portal'
|
||||
import {
|
||||
ARROW_HALF_SIZE,
|
||||
ARROW_SIZE,
|
||||
@@ -23,6 +25,33 @@ import {
|
||||
} from '#/components/Tooltip/const'
|
||||
import {Text} from '#/components/Typography'
|
||||
|
||||
const TooltipPortal = createPortalGroup()
|
||||
const TooltipProviderContext =
|
||||
createContext<React.RefObject<View | null> | null>(null)
|
||||
|
||||
/**
|
||||
* Provider for Tooltip component. Only needed when you need to position the tooltip relative to a container,
|
||||
* such as in the composer sheet.
|
||||
*
|
||||
* Only really necessary on iOS but can work on Android.
|
||||
*/
|
||||
export function SheetCompatProvider({children}: {children: React.ReactNode}) {
|
||||
const ref = useRef<View | null>(null)
|
||||
return (
|
||||
<GlobalGestureEventsProvider style={[a.flex_1]}>
|
||||
<TooltipPortal.Provider>
|
||||
<View ref={ref} collapsable={false} style={[a.flex_1]}>
|
||||
<TooltipProviderContext value={ref}>
|
||||
{children}
|
||||
</TooltipProviderContext>
|
||||
</View>
|
||||
<TooltipPortal.Outlet />
|
||||
</TooltipPortal.Provider>
|
||||
</GlobalGestureEventsProvider>
|
||||
)
|
||||
}
|
||||
SheetCompatProvider.displayName = 'TooltipSheetCompatProvider'
|
||||
|
||||
/**
|
||||
* These are native specific values, not shared with web
|
||||
*/
|
||||
@@ -120,22 +149,46 @@ export function Outer({
|
||||
|
||||
export function Target({children}: {children: React.ReactNode}) {
|
||||
const {shouldMeasure, setTargetMeasurements} = useContext(TargetContext)
|
||||
const [hasLayedOut, setHasLayedOut] = useState(false)
|
||||
const targetRef = useRef<View>(null)
|
||||
const containerRef = useContext(TooltipProviderContext)
|
||||
const keyboardIsOpen = useIsKeyboardVisible()
|
||||
|
||||
useEffect(() => {
|
||||
if (!shouldMeasure) return
|
||||
if (!shouldMeasure || !hasLayedOut) return
|
||||
/*
|
||||
* Once opened, measure the dimensions and position of the target
|
||||
*/
|
||||
targetRef.current?.measure((_x, _y, width, height, pageX, pageY) => {
|
||||
if (pageX !== undefined && pageY !== undefined && width && height) {
|
||||
setTargetMeasurements({x: pageX, y: pageY, width, height})
|
||||
}
|
||||
})
|
||||
}, [shouldMeasure, setTargetMeasurements])
|
||||
|
||||
if (containerRef?.current) {
|
||||
targetRef.current?.measureLayout(
|
||||
containerRef.current,
|
||||
(x, y, width, height) => {
|
||||
if (x !== undefined && y !== undefined && width && height) {
|
||||
setTargetMeasurements({x, y, width, height})
|
||||
}
|
||||
},
|
||||
)
|
||||
} else {
|
||||
targetRef.current?.measure((_x, _y, width, height, x, y) => {
|
||||
if (x !== undefined && y !== undefined && width && height) {
|
||||
setTargetMeasurements({x, y, width, height})
|
||||
}
|
||||
})
|
||||
}
|
||||
}, [
|
||||
shouldMeasure,
|
||||
setTargetMeasurements,
|
||||
hasLayedOut,
|
||||
containerRef,
|
||||
keyboardIsOpen,
|
||||
])
|
||||
|
||||
return (
|
||||
<View collapsable={false} ref={targetRef}>
|
||||
<View
|
||||
collapsable={false}
|
||||
ref={targetRef}
|
||||
onLayout={() => setHasLayedOut(true)}>
|
||||
{children}
|
||||
</View>
|
||||
)
|
||||
@@ -150,12 +203,15 @@ export function Content({
|
||||
}) {
|
||||
const {position, visible, onVisibleChange} = useContext(TooltipContext)
|
||||
const {targetMeasurements} = useContext(TargetContext)
|
||||
const isWithinProvider = !!useContext(TooltipProviderContext)
|
||||
const requestClose = useCallback(() => {
|
||||
onVisibleChange(false)
|
||||
}, [onVisibleChange])
|
||||
|
||||
if (!visible || !targetMeasurements) return null
|
||||
|
||||
const Portal = isWithinProvider ? TooltipPortal.Portal : RootPortal
|
||||
|
||||
return (
|
||||
<Portal>
|
||||
<Bubble
|
||||
|
||||
@@ -11,14 +11,19 @@ import {
|
||||
} from '#/components/Tooltip/const'
|
||||
import {Text} from '#/components/Typography'
|
||||
|
||||
// Portal Provider on native, but we actually don't need to do anything here
|
||||
export function Provider({children}: {children: React.ReactNode}) {
|
||||
return <>{children}</>
|
||||
}
|
||||
Provider.displayName = 'TooltipProvider'
|
||||
|
||||
type TooltipContextType = {
|
||||
position: 'top' | 'bottom'
|
||||
onVisibleChange: (open: boolean) => void
|
||||
}
|
||||
|
||||
const TooltipContext = createContext<TooltipContextType>({
|
||||
const TooltipContext = createContext<Pick<TooltipContextType, 'position'>>({
|
||||
position: 'bottom',
|
||||
onVisibleChange: () => {},
|
||||
})
|
||||
TooltipContext.displayName = 'TooltipContext'
|
||||
|
||||
@@ -33,10 +38,7 @@ export function Outer({
|
||||
visible: boolean
|
||||
onVisibleChange: (visible: boolean) => void
|
||||
}) {
|
||||
const ctx = useMemo(
|
||||
() => ({position, onVisibleChange}),
|
||||
[position, onVisibleChange],
|
||||
)
|
||||
const ctx = useMemo(() => ({position}), [position])
|
||||
return (
|
||||
<Popover.Root open={visible} onOpenChange={onVisibleChange}>
|
||||
<TooltipContext.Provider value={ctx}>{children}</TooltipContext.Provider>
|
||||
@@ -60,7 +62,7 @@ export function Content({
|
||||
label: string
|
||||
}) {
|
||||
const t = useTheme()
|
||||
const {position, onVisibleChange} = useContext(TooltipContext)
|
||||
const {position} = useContext(TooltipContext)
|
||||
return (
|
||||
<Popover.Portal>
|
||||
<Popover.Content
|
||||
@@ -69,7 +71,11 @@ export function Content({
|
||||
side={position}
|
||||
sideOffset={4}
|
||||
collisionPadding={MIN_EDGE_SPACE}
|
||||
onInteractOutside={() => onVisibleChange(false)}
|
||||
onInteractOutside={evt => {
|
||||
if (evt.type === 'dismissableLayer.focusOutside') {
|
||||
evt.preventDefault()
|
||||
}
|
||||
}}
|
||||
style={flatten([
|
||||
a.rounded_sm,
|
||||
select(t.name, {
|
||||
|
||||
Reference in New Issue
Block a user