-
Notifications
You must be signed in to change notification settings - Fork 1.3k
feat: Add support for origin-aware overlay animations #8681
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
devongovett
wants to merge
1
commit into
main
Choose a base branch
from
origin-aware-animation
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+153
−47
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Build successful! 🎉 |
## API Changes
react-aria-components/react-aria-components:Popover Popover {
aria-describedby?: string
aria-details?: string
aria-label?: string
aria-labelledby?: string
arrowBoundaryOffset?: number = 0
+ arrowRef?: RefObject<Element | null>
boundaryElement?: Element = document.body
children?: ChildrenOrFunction<PopoverRenderProps>
className?: ClassNameOrFunction<PopoverRenderProps>
containerPadding?: number = 12
defaultOpen?: boolean
isEntering?: boolean
isExiting?: boolean
isKeyboardDismissDisabled?: boolean = false
isNonModal?: boolean
isOpen?: boolean
maxHeight?: number
offset?: number = 8
onOpenChange?: (boolean) => void
placement?: Placement = 'bottom'
scrollRef?: RefObject<Element | null> = overlayRef
shouldCloseOnInteractOutside?: (Element) => boolean
shouldFlip?: boolean = true
shouldUpdatePosition?: boolean = true
slot?: string | null
style?: StyleOrFunction<PopoverRenderProps>
trigger?: string
triggerRef?: RefObject<Element | null>
} /react-aria-components:PopoverProps PopoverProps {
aria-describedby?: string
aria-details?: string
aria-label?: string
aria-labelledby?: string
arrowBoundaryOffset?: number = 0
+ arrowRef?: RefObject<Element | null>
boundaryElement?: Element = document.body
children?: ChildrenOrFunction<PopoverRenderProps>
className?: ClassNameOrFunction<PopoverRenderProps>
containerPadding?: number = 12
defaultOpen?: boolean
isEntering?: boolean
isExiting?: boolean
isKeyboardDismissDisabled?: boolean = false
isNonModal?: boolean
isOpen?: boolean
maxHeight?: number
offset?: number = 8
onOpenChange?: (boolean) => void
placement?: Placement = 'bottom'
scrollRef?: RefObject<Element | null> = overlayRef
shouldCloseOnInteractOutside?: (Element) => boolean
shouldFlip?: boolean = true
shouldUpdatePosition?: boolean = true
slot?: string | null
style?: StyleOrFunction<PopoverRenderProps>
trigger?: string
triggerRef?: RefObject<Element | null>
} @react-aria/overlays/@react-aria/overlays:AriaPositionProps AriaPositionProps {
arrowBoundaryOffset?: number = 0
+ arrowRef?: RefObject<Element | null>
arrowSize?: number = 0
boundaryElement?: Element = document.body
containerPadding?: number = 12
crossOffset?: number = 0
maxHeight?: number
offset?: number = 0
onClose?: () => void | null
overlayRef: RefObject<Element | null>
placement?: Placement = 'bottom'
scrollRef?: RefObject<Element | null> = overlayRef
shouldFlip?: boolean = true
shouldUpdatePosition?: boolean = true
targetRef: RefObject<Element | null>
} /@react-aria/overlays:PositionAria PositionAria {
arrowProps: DOMAttributes
overlayProps: DOMAttributes
placement: PlacementAxis | null
+ triggerOrigin: {
+ x: number
+ y: number
+} | null
updatePosition: () => void
} /@react-aria/overlays:AriaPopoverProps AriaPopoverProps {
arrowBoundaryOffset?: number = 0
+ arrowRef?: RefObject<Element | null>
arrowSize?: number = 0
boundaryElement?: Element = document.body
containerPadding?: number = 12
crossOffset?: number = 0
isKeyboardDismissDisabled?: boolean = false
isNonModal?: boolean
maxHeight?: number
offset?: number = 0
placement?: Placement = 'bottom'
popoverRef: RefObject<Element | null>
scrollRef?: RefObject<Element | null> = overlayRef
shouldCloseOnInteractOutside?: (Element) => boolean
shouldFlip?: boolean = true
shouldUpdatePosition?: boolean = true
triggerRef: RefObject<Element | null>
} /@react-aria/overlays:PopoverAria PopoverAria {
arrowProps: DOMAttributes
placement: PlacementAxis | null
popoverProps: DOMAttributes
+ triggerOrigin: {
+ x: number
+ y: number
+} | null
underlayProps: DOMAttributes
} @react-spectrum/overlays/@react-spectrum/overlays:Popover Popover {
UNSAFE_className?: string
UNSAFE_style?: CSSProperties
alignSelf?: Responsive<'auto' | 'normal' | 'start' | 'end' | 'center' | 'flex-start' | 'flex-end' | 'self-start' | 'self-end' | 'stretch'>
arrowBoundaryOffset?: number = 0
+ arrowRef?: RefObject<Element | null>
arrowSize?: number = 0
bottom?: Responsive<DimensionValue>
boundaryElement?: Element = document.body
children: ReactNode
containerPadding?: number = 12
crossOffset?: number = 0
disableFocusManagement?: boolean
enableBothDismissButtons?: boolean
end?: Responsive<DimensionValue>
flex?: Responsive<string | number | boolean>
flexBasis?: Responsive<number | string>
flexGrow?: Responsive<number>
flexShrink?: Responsive<number>
gridArea?: Responsive<string>
gridColumn?: Responsive<string>
gridColumnEnd?: Responsive<string>
gridColumnStart?: Responsive<string>
gridRow?: Responsive<string>
gridRowEnd?: Responsive<string>
gridRowStart?: Responsive<string>
groupRef?: RefObject<Element | null>
height?: Responsive<DimensionValue>
hideArrow?: boolean
isDisabled?: boolean
isHidden?: Responsive<boolean>
isKeyboardDismissDisabled?: boolean = false
isNonModal?: boolean
justifySelf?: Responsive<'auto' | 'normal' | 'start' | 'end' | 'flex-start' | 'flex-end' | 'self-start' | 'self-end' | 'center' | 'left' | 'right' | 'stretch'>
left?: Responsive<DimensionValue>
margin?: Responsive<DimensionValue>
marginBottom?: Responsive<DimensionValue>
marginEnd?: Responsive<DimensionValue>
marginStart?: Responsive<DimensionValue>
marginTop?: Responsive<DimensionValue>
marginX?: Responsive<DimensionValue>
marginY?: Responsive<DimensionValue>
maxHeight?: Responsive<DimensionValue>
maxWidth?: Responsive<DimensionValue>
minHeight?: Responsive<DimensionValue>
minWidth?: Responsive<DimensionValue>
offset?: number = 0
onBlurWithin?: (FocusEvent) => void
onDismissButtonPress?: () => void
onEnter?: () => void
onEntered?: () => void
onEntering?: () => void
onExit?: () => void
onExited?: () => void
onExiting?: () => void
onFocusWithin?: (FocusEvent) => void
onFocusWithinChange?: (boolean) => void
order?: Responsive<number>
placement?: Placement = 'bottom'
position?: Responsive<'static' | 'relative' | 'absolute' | 'fixed' | 'sticky'>
right?: Responsive<DimensionValue>
scrollRef?: RefObject<Element | null> = overlayRef
shouldCloseOnInteractOutside?: (Element) => boolean
shouldContainFocus?: boolean
shouldFlip?: boolean = true
shouldUpdatePosition?: boolean = true
start?: Responsive<DimensionValue>
state: OverlayTriggerState
top?: Responsive<DimensionValue>
triggerRef: RefObject<Element | null>
width?: Responsive<DimensionValue>
zIndex?: Responsive<number>
} @react-spectrum/s2/@react-spectrum/s2:PopoverProps PopoverProps {
UNSAFE_className?: UnsafeClassName
UNSAFE_style?: CSSProperties
aria-describedby?: string
aria-details?: string
aria-label?: string
aria-labelledby?: string
+ arrowRef?: RefObject<Element | null>
boundaryElement?: Element = document.body
children?: ChildrenOrFunction<PopoverRenderProps>
className?: ClassNameOrFunction<PopoverRenderProps>
containerPadding?: number = 12
defaultOpen?: boolean
hideArrow?: boolean = false
isEntering?: boolean
isExiting?: boolean
isOpen?: boolean
maxHeight?: number
offset?: number = 8
onOpenChange?: (boolean) => void
placement?: Placement = 'bottom'
scrollRef?: RefObject<Element | null> = overlayRef
shouldFlip?: boolean = true
size?: 'S' | 'M' | 'L'
slot?: string | null
style?: StyleOrFunction<PopoverRenderProps>
styles?: StyleString
trigger?: string
triggerRef?: RefObject<Element | null>
} |
snowystinger
approved these changes
Aug 7, 2025
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Fixes #8291, closes #8119, closes #6825
As discussed in #8163 (comment), this adds a
--trigger-origin
CSS variable to popovers and tooltips that has the position of the trigger relative to the overlay. This variable can be used withtransform-origin
to make origin-aware animations (e.g. scale).If the overlay has an arrow, the arrow position is used as the origin so that it does not appear to move during an animation. Otherwise, the corner of the trigger is used.
Also fixes scale animations from affecting positioning by skipping re-positioning while positioning is occurring.
Test instructions
Open the RAC Popover and Tooltip stories and test the enter/exit animations with various placements in the controls.