Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions packages/@react-spectrum/actionbar/src/ActionBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {FocusScope} from '@react-aria/focus';
// @ts-ignore
import intlMessages from '../intl/*.json';
import {OpenTransition} from '@react-spectrum/overlays';
import React, {ReactElement, useEffect, useRef} from 'react';
import React, {ReactElement, Ref, useEffect, useRef} from 'react';
import {SpectrumActionBarProps} from '@react-types/actionbar';
import styles from './actionbar.css';
import {Text} from '@react-spectrum/text';
Expand All @@ -31,13 +31,15 @@ import {useProviderProps} from '@react-spectrum/provider';

function ActionBar<T extends object>(props: SpectrumActionBarProps<T>, ref: DOMRef<HTMLDivElement>) {
let isOpen = props.selectedItemCount !== 0;
let domRef = useDOMRef(ref);

return (
<OpenTransition
nodeRef={domRef}
in={isOpen}
mountOnEnter
unmountOnExit>
<ActionBarInnerWithRef {...props} ref={ref} />
<ActionBarInnerWithRef {...props} ref={domRef} />
</OpenTransition>
);
}
Expand All @@ -46,7 +48,7 @@ interface ActionBarInnerProps<T> extends SpectrumActionBarProps<T> {
isOpen?: boolean
}

function ActionBarInner<T>(props: ActionBarInnerProps<T>, ref: DOMRef<HTMLDivElement>) {
function ActionBarInner<T>(props: ActionBarInnerProps<T>, ref: Ref<HTMLDivElement>) {
props = useProviderProps(props);

let {
Expand All @@ -59,7 +61,6 @@ function ActionBarInner<T>(props: ActionBarInnerProps<T>, ref: DOMRef<HTMLDivEle
} = props;

let {styleProps} = useStyleProps(props);
let domRef = useDOMRef(ref);
let stringFormatter = useLocalizedStringFormatter(intlMessages);

// Store the last count greater than zero in a ref so that we can retain it while rendering the fade-out animation.
Expand Down Expand Up @@ -88,7 +89,7 @@ function ActionBarInner<T>(props: ActionBarInnerProps<T>, ref: DOMRef<HTMLDivEle
{...filterDOMProps(props)}
{...styleProps}
{...keyboardProps}
ref={domRef}
ref={ref}
className={classNames(
styles,
'react-spectrum-ActionBar', {
Expand Down Expand Up @@ -127,7 +128,7 @@ function ActionBarInner<T>(props: ActionBarInnerProps<T>, ref: DOMRef<HTMLDivEle
);
}

const ActionBarInnerWithRef = React.forwardRef(ActionBarInner) as <T>(props: SpectrumActionBarProps<T> & {ref?: DOMRef<HTMLDivElement>}) => ReturnType<typeof ActionBarInner>;
const ActionBarInnerWithRef = React.forwardRef(ActionBarInner) as <T>(props: ActionBarInnerProps<T> & {ref?: Ref<HTMLDivElement>}) => ReactElement;

/**
* TODO: Add description of component here.
Expand Down
20 changes: 11 additions & 9 deletions packages/@react-spectrum/overlays/src/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,27 +18,29 @@ import {Overlay} from './Overlay';
import {OverlayProps} from '@react-types/overlays';
import {OverlayTriggerState} from '@react-stately/overlays';
import overrideStyles from './overlays.css';
import React, {forwardRef, ReactNode, RefObject} from 'react';
import React, {forwardRef, MutableRefObject, ReactNode, RefObject, useRef} from 'react';
import {Underlay} from './Underlay';
import {useViewportSize} from '@react-aria/utils';

interface ModalProps extends AriaModalOverlayProps, StyleProps, OverlayProps {
interface ModalProps extends AriaModalOverlayProps, StyleProps, Omit<OverlayProps, 'nodeRef'> {
children: ReactNode,
state: OverlayTriggerState,
type?: 'modal' | 'fullscreen' | 'fullscreenTakeover'
}

interface ModalWrapperProps extends ModalProps {
isOpen?: boolean
isOpen?: boolean,
wrapperRef: MutableRefObject<HTMLDivElement>
}

function Modal(props: ModalProps, ref: DOMRef<HTMLDivElement>) {
let {children, state, ...otherProps} = props;
let domRef = useDOMRef(ref);
let wrapperRef = useRef<HTMLDivElement>(null);

return (
<Overlay {...otherProps} isOpen={state.isOpen}>
<ModalWrapper {...props} ref={domRef}>
<Overlay {...otherProps} isOpen={state.isOpen} nodeRef={wrapperRef}>
<ModalWrapper {...props} wrapperRef={wrapperRef} ref={domRef}>
{children}
</ModalWrapper>
</Overlay>
Expand All @@ -51,10 +53,9 @@ let typeMap = {
};

let ModalWrapper = forwardRef(function (props: ModalWrapperProps, ref: RefObject<HTMLDivElement>) {
let {type, children, state, isOpen} = props;
let {type, children, state, isOpen, wrapperRef} = props;
let typeVariant = typeMap[type];
let {styleProps} = useStyleProps(props);

let {modalProps, underlayProps} = useModalOverlay(props, state, ref);

let wrapperClassName = classNames(
Expand Down Expand Up @@ -87,8 +88,9 @@ let ModalWrapper = forwardRef(function (props: ModalWrapperProps, ref: RefObject
'--spectrum-visual-viewport-height': viewport.height + 'px'
};

// Attach Transition's nodeRef to outer most wrapper for node.reflow: https://github.com/reactjs/react-transition-group/blob/c89f807067b32eea6f68fd6c622190d88ced82e2/src/Transition.js#L231
return (
<>
<div ref={wrapperRef}>
<Underlay {...underlayProps} isOpen={isOpen} />
<div className={wrapperClassName} style={style}>
<div
Expand All @@ -100,7 +102,7 @@ let ModalWrapper = forwardRef(function (props: ModalWrapperProps, ref: RefObject
{children}
</div>
</div>
</>
</div>
);
});

Expand Down
5 changes: 3 additions & 2 deletions packages/@react-spectrum/overlays/src/Overlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import React, {useCallback, useState} from 'react';
import {Overlay as ReactAriaOverlay} from '@react-aria/overlays';

function Overlay(props: OverlayProps, ref: DOMRef<HTMLDivElement>) {
let {children, isOpen, container, onEnter, onEntering, onEntered, onExit, onExiting, onExited} = props;
let {children, isOpen, container, onEnter, onEntering, onEntered, onExit, onExiting, onExited, nodeRef} = props;
let [exited, setExited] = useState(!isOpen);

let handleEntered = useCallback(() => {
Expand Down Expand Up @@ -53,7 +53,8 @@ function Overlay(props: OverlayProps, ref: DOMRef<HTMLDivElement>) {
onExited={handleExited}
onEnter={onEnter}
onEntering={onEntering}
onEntered={handleEntered}>
onEntered={handleEntered}
nodeRef={nodeRef}>
{children}
</OpenTransition>
</Provider>
Expand Down
18 changes: 11 additions & 7 deletions packages/@react-spectrum/overlays/src/Popover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {DOMRef, StyleProps} from '@react-types/shared';
import {Overlay} from './Overlay';
import {OverlayTriggerState} from '@react-stately/overlays';
import overrideStyles from './overlays.css';
import React, {forwardRef, ReactNode, RefObject, useRef, useState} from 'react';
import React, {forwardRef, MutableRefObject, ReactNode, RefObject, useRef, useState} from 'react';
import styles from '@adobe/spectrum-css-temp/components/popover/vars.css';
import {Underlay} from './Underlay';
import {useLayoutEffect} from '@react-aria/utils';
Expand All @@ -28,7 +28,8 @@ interface PopoverProps extends Omit<AriaPopoverProps, 'popoverRef' | 'maxHeight'
}

interface PopoverWrapperProps extends PopoverProps {
isOpen?: boolean
isOpen?: boolean,
wrapperRef: MutableRefObject<HTMLDivElement>
}

/**
Expand All @@ -52,10 +53,11 @@ function Popover(props: PopoverProps, ref: DOMRef<HTMLDivElement>) {
...otherProps
} = props;
let domRef = useDOMRef(ref);
let wrapperRef = useRef<HTMLDivElement>(null);

return (
<Overlay {...otherProps} isOpen={state.isOpen}>
<PopoverWrapper ref={domRef} {...props}>
<Overlay {...otherProps} isOpen={state.isOpen} nodeRef={wrapperRef}>
<PopoverWrapper ref={domRef} {...props} wrapperRef={wrapperRef}>
{children}
</PopoverWrapper>
</Overlay>
Expand All @@ -68,7 +70,8 @@ const PopoverWrapper = forwardRef((props: PopoverWrapperProps, ref: RefObject<HT
isOpen,
hideArrow,
isNonModal,
state
state,
wrapperRef
} = props;
let {styleProps} = useStyleProps(props);

Expand All @@ -78,8 +81,9 @@ const PopoverWrapper = forwardRef((props: PopoverWrapperProps, ref: RefObject<HT
maxHeight: null
}, state);

// Attach Transition's nodeRef to outer most wrapper for node.reflow: https://github.com/reactjs/react-transition-group/blob/c89f807067b32eea6f68fd6c622190d88ced82e2/src/Transition.js#L231
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you add the comment here and not to Modal.tsx or Tray.txs?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No particular reason, I can definitely add that to those components as well

return (
<>
<div ref={wrapperRef}>
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could instead attach the nodeRef to the Underlay, however it doesn't exist in the isNonModal case with popover. Adding a wrapping div should be safe because Underlay and the overlay (Popover, Tray, Modal) all use position: fixed or position: absolute

{!isNonModal && <Underlay isTransparent {...underlayProps} isOpen={isOpen} /> }
<div
{...styleProps}
Expand Down Expand Up @@ -115,7 +119,7 @@ const PopoverWrapper = forwardRef((props: PopoverWrapperProps, ref: RefObject<HT
)}
<DismissButton onDismiss={state.close} />
</div>
</>
</div>
);
});

Expand Down
20 changes: 12 additions & 8 deletions packages/@react-spectrum/overlays/src/Tray.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,30 @@ import {Overlay} from './Overlay';
import {OverlayProps} from '@react-types/overlays';
import {OverlayTriggerState} from '@react-stately/overlays';
import overrideStyles from './overlays.css';
import React, {forwardRef, ReactNode, RefObject} from 'react';
import React, {forwardRef, MutableRefObject, ReactNode, RefObject, useRef} from 'react';
import trayStyles from '@adobe/spectrum-css-temp/components/tray/vars.css';
import {Underlay} from './Underlay';
import {useViewportSize} from '@react-aria/utils';

interface TrayProps extends AriaModalOverlayProps, StyleProps, OverlayProps {
interface TrayProps extends AriaModalOverlayProps, StyleProps, Omit<OverlayProps, 'nodeRef'> {
children: ReactNode,
state: OverlayTriggerState,
isFixedHeight?: boolean
}

interface TrayWrapperProps extends TrayProps {
isOpen?: boolean
isOpen?: boolean,
wrapperRef: MutableRefObject<HTMLDivElement>
}

function Tray(props: TrayProps, ref: DOMRef<HTMLDivElement>) {
let {children, state, ...otherProps} = props;
let domRef = useDOMRef(ref);
let wrapperRef = useRef<HTMLDivElement>(null);

return (
<Overlay {...otherProps} isOpen={state.isOpen}>
<TrayWrapper {...props} ref={domRef}>
<Overlay {...otherProps} isOpen={state.isOpen} nodeRef={wrapperRef}>
<TrayWrapper {...props} wrapperRef={wrapperRef} ref={domRef}>
{children}
</TrayWrapper>
</Overlay>
Expand All @@ -50,7 +52,8 @@ let TrayWrapper = forwardRef(function (props: TrayWrapperProps, ref: RefObject<H
children,
isOpen,
isFixedHeight,
state
state,
wrapperRef
} = props;
let {styleProps} = useStyleProps(props);

Expand Down Expand Up @@ -91,8 +94,9 @@ let TrayWrapper = forwardRef(function (props: TrayWrapperProps, ref: RefObject<H
styleProps.className
);

// Attach Transition's nodeRef to outer most wrapper for node.reflow: https://github.com/reactjs/react-transition-group/blob/c89f807067b32eea6f68fd6c622190d88ced82e2/src/Transition.js#L231
return (
<>
<div ref={wrapperRef}>
<Underlay {...underlayProps} isOpen={isOpen} />
<div className={wrapperClassName} style={wrapperStyle}>
<div
Expand All @@ -106,7 +110,7 @@ let TrayWrapper = forwardRef(function (props: TrayWrapperProps, ref: RefObject<H
<DismissButton onDismiss={state.close} />
</div>
</div>
</>
</div>
);
});

Expand Down
5 changes: 2 additions & 3 deletions packages/@react-spectrum/tooltip/src/TooltipTrigger.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ function TooltipTrigger(props: SpectrumTooltipTriggerProps) {
trigger: triggerAction
} = props;

let [trigger, tooltip] = React.Children.toArray(children);

let [trigger, tooltip] = React.Children.toArray(children) as [ReactElement, ReactElement];
let state = useTooltipTriggerState(props);

let tooltipTriggerRef = useRef<HTMLElement>();
Expand Down Expand Up @@ -68,7 +67,7 @@ function TooltipTrigger(props: SpectrumTooltipTriggerProps) {
arrowProps,
...tooltipProps
}}>
<Overlay isOpen={state.isOpen}>
<Overlay isOpen={state.isOpen} nodeRef={overlayRef}>
{tooltip}
</Overlay>
</TooltipContext.Provider>
Expand Down
11 changes: 6 additions & 5 deletions packages/@react-types/overlays/src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
* governing permissions and limitations under the License.
*/

import {HTMLAttributes, ReactElement, ReactNode} from 'react';
import {HTMLAttributes, MutableRefObject, ReactElement, ReactNode} from 'react';
import {StyleProps} from '@react-types/shared';

export type Placement = 'bottom' | 'bottom left' | 'bottom right' | 'bottom start' | 'bottom end' |
Expand Down Expand Up @@ -71,18 +71,19 @@ export interface OverlayProps {
onEntered?: () => void,
onExit?: () => void,
onExiting?: () => void,
onExited?: () => void
onExited?: () => void,
nodeRef: MutableRefObject<HTMLElement>
}

export interface ModalProps extends StyleProps, OverlayProps {
export interface ModalProps extends StyleProps, Omit<OverlayProps, 'nodeRef'> {
children: ReactElement,
isOpen?: boolean,
onClose?: () => void,
type?: 'modal' | 'fullscreen' | 'fullscreenTakeover',
isDismissable?: boolean
}

export interface PopoverProps extends StyleProps, OverlayProps {
export interface PopoverProps extends StyleProps, Omit<OverlayProps, 'nodeRef'> {
children: ReactNode,
placement?: PlacementAxis,
arrowProps?: HTMLAttributes<HTMLElement>,
Expand All @@ -94,7 +95,7 @@ export interface PopoverProps extends StyleProps, OverlayProps {
isDismissable?: boolean
}

export interface TrayProps extends StyleProps, OverlayProps {
export interface TrayProps extends StyleProps, Omit<OverlayProps, 'nodeRef'> {
children: ReactElement,
isOpen?: boolean,
onClose?: () => void,
Expand Down