Skip to content

Commit

Permalink
fix: PopupContent to properly pass ref (microsoft#20866)
Browse files Browse the repository at this point in the history
* fix: PopupContent to properly pass ref

* add changelog

* fix ref placement

* fix: ref placement

* handle inner ref for foxus components

* apply review

* fix proptype

* fix popup ref
  • Loading branch information
chpalac authored and Marion Le Pontois committed Jan 17, 2022
1 parent c5c1d3f commit f9be9a1
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 12 deletions.
1 change: 1 addition & 0 deletions packages/fluentui/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- Fix `Loader` component to properly pass ref to root slots @chpalac ([#20814](https://github.com/microsoft/fluentui/pull/20814))
- Fix `Label` component to properly pass ref to root slots @chpalac ([#20813](https://github.com/microsoft/fluentui/pull/20813))
- Fix `MenuItemIcon` to allow icon `size` to be in effect @yuanboxue-amber ([#20803](https://github.com/microsoft/fluentui/pull/20803))
- Fix `PopupContent` component to properly pass ref to root slots @chpalac ([#20866](https://github.com/microsoft/fluentui/pull/20866))
- Fix `Pill` components to properly pass ref to root slots @chpalac ([#20838](https://github.com/microsoft/fluentui/pull/20838))
- Fix `MenuButton` component to properly pass ref to root slots @chpalac ([#20837](https://github.com/microsoft/fluentui/pull/20837))
- Fix `getPointerStyles` transform for RTL @chpalac ([#20915](https://github.com/microsoft/fluentui/pull/20915))
Expand Down
15 changes: 11 additions & 4 deletions packages/fluentui/react-bindings/src/FocusZone/AutoFocusZone.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Ref } from '@fluentui/react-component-ref';
import { handleRef } from '@fluentui/react-component-ref';
import { callable } from '@fluentui/styles';
import * as React from 'react';
import * as PropTypes from 'prop-types';
Expand All @@ -16,6 +16,7 @@ export class AutoFocusZone extends React.Component<AutoFocusZoneProps> {
static propTypes = {
as: PropTypes.elementType,
firstFocusableSelector: PropTypes.oneOfType([PropTypes.func, PropTypes.string]),
innerRef: PropTypes.any,
};

static handledProps = _.keys(AutoFocusZone.propTypes) as any;
Expand All @@ -29,9 +30,15 @@ export class AutoFocusZone extends React.Component<AutoFocusZoneProps> {
const ElementType = getElementType(this.props);

return (
<Ref innerRef={this.root}>
<ElementType {...unhandledProps}>{this.props.children}</ElementType>
</Ref>
<ElementType
ref={(element: HTMLElement) => {
handleRef(this.root, element);
handleRef(this.props.innerRef, element);
}}
{...unhandledProps}
>
{this.props.children}
</ElementType>
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ export interface AutoFocusZoneProps extends React.HTMLAttributes<HTMLDivElement>
* Indicates the selector for first focusable item. By default, the first tabbable element will get focus.
*/
firstFocusableSelector?: string | (() => string);

innerRef?: React.Ref<any>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
HIDDEN_FROM_ACC_TREE,
} from './focusUtilities';
import { FocusTrapZoneProps } from './FocusTrapZone.types';
import { handleRef } from '@fluentui/react-component-ref';

/** FocusTrapZone is used to trap the focus in any html element placed in body
* and hide other elements outside of Focus Trap Zone from accessibility tree.
Expand Down Expand Up @@ -56,6 +57,7 @@ export class FocusTrapZone extends React.Component<FocusTrapZoneProps, {}> {
disableFirstFocus: PropTypes.bool,
focusPreviouslyFocusedInnerElement: PropTypes.bool,
focusTriggerOnOutsideClick: PropTypes.bool,
innerRef: PropTypes.any,
};

static defaultProps: FocusTrapZoneProps = {
Expand Down Expand Up @@ -140,7 +142,10 @@ export class FocusTrapZone extends React.Component<FocusTrapZoneProps, {}> {
<ElementType
{...unhandledProps}
className={className}
ref={this.createRef}
ref={(element: HTMLElement) => {
this.createRef(element);
handleRef(this.props.innerRef, element);
}}
aria-labelledby={ariaLabelledBy}
onKeyDown={this._onKeyboardHandler}
onFocusCapture={this._onFocusCapture}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,6 @@ export interface FocusTrapZoneProps extends React.HTMLAttributes<HTMLDivElement>
* If it has never had a focused descendant before, behavior falls back to the first focused descendant.
*/
focusPreviouslyFocusedInnerElement?: boolean;

innerRef?: any;
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Accessibility } from '@fluentui/accessibility';
import {
ComponentWithAs,
AutoFocusZone,
AutoFocusZoneProps,
FocusTrapZone,
Expand All @@ -11,6 +10,7 @@ import {
useStyles,
useTelemetry,
useUnhandledProps,
ForwardRefWithAs,
} from '@fluentui/react-bindings';
import * as customPropTypes from '@fluentui/react-proptypes';
import * as PopperJs from '@popperjs/core';
Expand Down Expand Up @@ -90,8 +90,7 @@ export const popupContentSlotClassNames: PopupContentSlotClassNames = {
/**
* A PopupContent displays the content of a Popup component.
*/
export const PopupContent: ComponentWithAs<'div', PopupContentProps> &
FluentComponentStaticProps<PopupContentProps> = props => {
export const PopupContent = (React.forwardRef<HTMLDivElement, PopupContentProps>((props, ref) => {
const context = useFluentContext();
const { setStart, setEnd } = useTelemetry(PopupContent.displayName, context.telemetry);
setStart();
Expand Down Expand Up @@ -162,22 +161,35 @@ export const PopupContent: ComponentWithAs<'div', PopupContentProps> &
...((_.keys(trapFocus).length && trapFocus) as FocusTrapZoneProps),
as: ElementType,
};
element = <FocusTrapZone {...focusTrapZoneProps}>{popupContent}</FocusTrapZone>;
element = (
<FocusTrapZone innerRef={ref} {...focusTrapZoneProps}>
{popupContent}
</FocusTrapZone>
);
} else if (autoFocus) {
const autoFocusZoneProps = {
...popupContentProps,
...((_.keys(autoFocus).length && autoFocus) as AutoFocusZoneProps),
as: ElementType,
};
element = <AutoFocusZone {...autoFocusZoneProps}>{popupContent}</AutoFocusZone>;
element = (
<AutoFocusZone innerRef={ref} {...autoFocusZoneProps}>
{popupContent}
</AutoFocusZone>
);
} else {
element = <ElementType {...popupContentProps}>{popupContent}</ElementType>;
element = (
<ElementType ref={ref} {...popupContentProps}>
{popupContent}
</ElementType>
);
}

setEnd();

return element;
};
}) as unknown) as ForwardRefWithAs<'div', HTMLDivElement, PopupContentProps> &
FluentComponentStaticProps<PopupContentProps>;

PopupContent.displayName = 'PopupContent';

Expand Down

0 comments on commit f9be9a1

Please sign in to comment.