Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"changes": [
{
"packageName": "office-ui-fabric-react",
"comment": "Fixes useTargetWidth prop for ContextualMenu",
"type": "patch"
}
],
"packageName": "office-ui-fabric-react",
"email": "joem@microsoft.com"
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export interface IContextualMenuState {
slideDirectionalClassName?: string;
subMenuId?: string;
submenuDirection?: DirectionalHint;
targetWidth?: number;
}

export function hasSubmenu(item: IContextualMenuItem) {
Expand Down Expand Up @@ -153,13 +154,15 @@ export class ContextualMenu extends BaseComponent<IContextualMenuProps, IContext
if (newProps.target !== this.props.target) {
let newTarget = newProps.target;
this._setTargetWindowAndElement(newTarget!);
this._setTargetWidthAsync();
}
}

// Invoked once, both on the client and server, immediately before the initial rendering occurs.
public componentWillMount() {
let target = this.props.target;
this._setTargetWindowAndElement(target!);
this._setTargetWidthAsync();
this._previousActiveElement = this._targetWindow ? this._targetWindow.document.activeElement as HTMLElement : null;
}

Expand Down Expand Up @@ -246,15 +249,14 @@ export class ContextualMenu extends BaseComponent<IContextualMenuProps, IContext
*/
let contextMenuStyle;
let targetAsHtmlElement = this._target as HTMLElement;
if ((useTargetWidth || useTargetAsMinWidth) && targetAsHtmlElement && targetAsHtmlElement.offsetWidth) {
let targetWidth = targetAsHtmlElement.offsetWidth;
if ((useTargetWidth || useTargetAsMinWidth) && targetAsHtmlElement) {
if (useTargetWidth) {
contextMenuStyle = {
width: targetWidth
width: this.state.targetWidth
};
} else if (useTargetAsMinWidth) {
contextMenuStyle = {
minWidth: targetWidth
minWidth: this.state.targetWidth
};
}
}
Expand All @@ -271,7 +273,7 @@ export class ContextualMenu extends BaseComponent<IContextualMenuProps, IContext
}
return (
<Callout
{...calloutProps}
{ ...calloutProps }
target={ useTargetPoint ? targetPoint : target }
isBeakVisible={ isBeakVisible }
beakWidth={ beakWidth }
Expand Down Expand Up @@ -330,6 +332,23 @@ export class ContextualMenu extends BaseComponent<IContextualMenuProps, IContext
}
}

private _setTargetWidthAsync() {

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.

@joschect Here's the attempt at asynchronously getting the target's width. Let me know what you think.

const targetAsHtmlElement = this._target as HTMLElement;

// If component doesn't care about target's width, then this is a no-op.
if ((!this.props.useTargetWidth && !this.props.useTargetAsMinWidth) || !targetAsHtmlElement) {
return;
}

this._async.requestAnimationFrame(() => {
const targetBoundingRect = targetAsHtmlElement.getBoundingClientRect();

this.setState({
targetWidth: targetBoundingRect.width - 2 /* Need to account for border width */

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.

targetWidth [](start = 8, length = 11)

Since this async, how do we make sure this value is set when the render API is called?

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.

It gets called in componentWillMount, so the value should be available in the render function. We'll have this issue either way since @joschect said even reading offsetWidth should be moved to an async function. Can someone more familiar with this pattern in OUFR help solve the problem? Do you have any suggestions, @manishgarg1?

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.

Or if you have a better way to solve it, feel free to take it over. The issue has been open since November with no activity and we need a fix. Thanks!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It's okay if the value is not set at first render, although it may cause apparent resizing. You would need to provide a default value though.

});
});
}

private _onRenderSubMenu(subMenuProps: IContextualMenuProps) {
return <ContextualMenu { ...subMenuProps } />;
}
Expand Down