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
1 change: 1 addition & 0 deletions UNRELEASED.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

- Fixed an issue with the `Filters` component where the `aria-expanded` attribute was `undefined` on mount ([#2589]https://github.com/Shopify/polaris-react/pull/2589)
- Fixed `TrapFocus` from tabbing out of the container ([#2555](https://github.com/Shopify/polaris-react/pull/2555))
- Fixed `PositionedOverlay` not correctly getting its position when aligned to the right of the activator ([#2587](https://github.com/Shopify/polaris-react/pull/2587))

### Documentation

Expand Down
2 changes: 1 addition & 1 deletion src/components/Popover/Popover.scss
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ $content-max-width: rem(400px);
}

.positionedAbove {
margin: spacing() 0 $visible-portion-of-arrow spacing(tight);
margin: spacing() spacing(tight) $visible-portion-of-arrow;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure why we needed to remove the right margin when positioned above.


&.fullWidth {
margin: 0 0 $visible-portion-of-arrow;
Expand Down
39 changes: 28 additions & 11 deletions src/components/PositionedOverlay/PositionedOverlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ export {PreferredPosition, PreferredAlignment};
export type Positioning = 'above' | 'below';

export interface OverlayDetails {
left: number;
left?: number;
right?: number;
desiredHeight: number;
positioning: Positioning;
measuring: boolean;
Expand All @@ -44,7 +45,8 @@ export interface PositionedOverlayProps {
interface State {
measuring: boolean;
activatorRect: Rect;
left: number;
left?: number;
right?: number;
top: number;
height: number;
width: number | null;
Expand All @@ -63,7 +65,8 @@ export class PositionedOverlay extends React.PureComponent<
state: State = {
measuring: true,
activatorRect: getRectForNode(this.props.activator),
left: 0,
right: undefined,
left: undefined,
top: 0,
height: 0,
width: null,
Expand Down Expand Up @@ -118,12 +121,13 @@ export class PositionedOverlay extends React.PureComponent<
}

render() {
const {left, top, zIndex, width} = this.state;
const {left, right, top, zIndex, width} = this.state;
const {render, fixed, classNames: propClassNames} = this.props;

const style = {
top: top == null || isNaN(top) ? undefined : top,
left: left == null || isNaN(left) ? undefined : left,
right: right == null || isNaN(right) ? undefined : right,
width: width == null || isNaN(width) ? undefined : width,
zIndex: zIndex == null || isNaN(zIndex) ? undefined : zIndex,
};
Expand All @@ -143,11 +147,19 @@ export class PositionedOverlay extends React.PureComponent<
}

private overlayDetails = (): OverlayDetails => {
const {measuring, left, positioning, height, activatorRect} = this.state;
const {
measuring,
left,
right,
positioning,
height,
activatorRect,
} = this.state;

return {
measuring,
left,
right,
desiredHeight: height,
positioning,
activatorRect,
Expand All @@ -164,8 +176,9 @@ export class PositionedOverlay extends React.PureComponent<
this.observer.disconnect();

this.setState(
({left, top}) => ({
({left, top, right}) => ({
left,
right,
top,
height: 0,
positioning: 'below',
Expand Down Expand Up @@ -209,6 +222,7 @@ export class PositionedOverlay extends React.PureComponent<
const overlayMargins = this.overlay.firstElementChild
? getMarginsForNode(this.overlay.firstElementChild as HTMLElement)
: {activator: 0, container: 0, horizontal: 0};

const containerRect = windowRect();
const zIndexForLayer = getZIndexForLayerFromNode(activator);
const zIndex =
Expand All @@ -234,7 +248,10 @@ export class PositionedOverlay extends React.PureComponent<
{
measuring: false,
activatorRect: getRectForNode(activator),
left: horizontalPosition,
left:
preferredAlignment !== 'right' ? horizontalPosition : undefined,
right:
Copy link
Contributor Author

@dleroux dleroux Jan 3, 2020

Choose a reason for hiding this comment

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

We're only going to go from the right if the preferred alignment is right.

preferredAlignment === 'right' ? horizontalPosition : undefined,
top: lockPosition ? top : verticalPosition.top,
lockPosition: Boolean(fixed),
height: verticalPosition.height || 0,
Expand Down Expand Up @@ -278,9 +295,9 @@ export function intersectionWithViewport(
function getMarginsForNode(node: HTMLElement) {
const nodeStyles = window.getComputedStyle(node);
return {
activator: parseFloat(nodeStyles.marginTop || ''),
container: parseFloat(nodeStyles.marginBottom || ''),
horizontal: parseFloat(nodeStyles.marginLeft || ''),
activator: parseFloat(nodeStyles.marginTop || '0'),
container: parseFloat(nodeStyles.marginBottom || '0'),
horizontal: parseFloat(nodeStyles.marginLeft || '0'),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

defaulting to 0. an empty string didn't make sense for the tests.

};
}

Expand All @@ -298,7 +315,7 @@ function windowRect() {
top: window.scrollY,
left: window.scrollX,
height: window.innerHeight,
width: window.innerWidth,
width: document.body.clientWidth,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

window.innerWidth includes the scrollbars, We don't want this when aligning from the right and it's shouldn't impact the left.

Copy link
Member

Choose a reason for hiding this comment

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

TIL! Will this change alone fix the measuring then and the other stuff in this PR is just a nice to have?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, the right positioning is what is needed. I'll write it in the description.

});
}

Expand Down
14 changes: 14 additions & 0 deletions src/components/PositionedOverlay/tests/PositionedOverlay.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,20 @@ describe('<PositionedOverlay />', () => {
<PositionedOverlay {...mockProps} preferredAlignment="left" />,
);

expect((positionedOverlay.find('div').prop('style') as any).left).toBe(0);
expect(
(positionedOverlay.find('div').prop('style') as any).right,
).toBeUndefined();
});

it('aligns right if preferredAlignment is given', () => {
const positionedOverlay = mountWithAppProvider(
<PositionedOverlay {...mockProps} preferredAlignment="right" />,
);

expect((positionedOverlay.find('div').prop('style') as any).right).toBe(
0,
);
expect(
(positionedOverlay.find('div').prop('style') as any).left,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This test didn't make sense. No matter whar left would be undefined, which it shouldn't be.

).toBeUndefined();
Expand Down
9 changes: 4 additions & 5 deletions src/components/PositionedOverlay/utilities/math.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,13 +98,12 @@ export function calculateHorizontalPosition(
Math.max(0, activatorRect.left - overlayMargins.horizontal),
);
} else if (preferredAlignment === 'right') {
const activatorRight = activatorRect.left + activatorRect.width;
const activatorRight =
containerRect.width - (activatorRect.left + activatorRect.width);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

the right position calculation.


return Math.min(
maximum,
Math.max(
0,
activatorRight - overlayRect.width + overlayMargins.horizontal,
),
Math.max(0, activatorRight - overlayMargins.horizontal),
);
}

Expand Down
4 changes: 4 additions & 0 deletions src/components/Scrollable/Scrollable.scss
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ $shadow-top: inset 0 $shadow-size $shadow-size (-1 * $shadow-size)
overflow-y: auto;
}

.verticalHasScrolling {
overflow-y: scroll;
}

.hasTopShadow {
box-shadow: $shadow-top;
}
Expand Down
6 changes: 5 additions & 1 deletion src/components/Scrollable/Scrollable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ interface State {
topShadow: boolean;
bottomShadow: boolean;
scrollPosition: number;
canScroll: boolean;
}

export class Scrollable extends React.Component<ScrollableProps, State> {
Expand All @@ -56,6 +57,7 @@ export class Scrollable extends React.Component<ScrollableProps, State> {
topShadow: false,
bottomShadow: false,
scrollPosition: 0,
canScroll: false,
};

private stickyManager = new StickyManager();
Expand Down Expand Up @@ -104,7 +106,7 @@ export class Scrollable extends React.Component<ScrollableProps, State> {
}

render() {
const {topShadow, bottomShadow} = this.state;
const {topShadow, bottomShadow, canScroll} = this.state;
const {
children,
className,
Expand All @@ -123,6 +125,7 @@ export class Scrollable extends React.Component<ScrollableProps, State> {
horizontal && styles.horizontal,
topShadow && styles.hasTopShadow,
bottomShadow && styles.hasBottomShadow,
vertical && canScroll && styles.verticalHasScrolling,
);

return (
Expand Down Expand Up @@ -168,6 +171,7 @@ export class Scrollable extends React.Component<ScrollableProps, State> {
topShadow: shouldTopShadow,
bottomShadow: shouldBottomShadow,
scrollPosition: scrollTop,
canScroll,
});
};

Expand Down
1 change: 1 addition & 0 deletions src/components/TopBar/components/Menu/Menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export function Menu(props: MenuProps) {
onClose={onClose}
fixed
fullHeight={isFullHeight}
preferredAlignment="right"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The user menu was causing the issue. This fixed it.

>
<ActionList onActionAnyItem={onClose} sections={actions} />
{messageMarkup}
Expand Down