Skip to content
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

[WIP] Fix PositionOverlay width issue for the menu in TopBar #1692

Closed
wants to merge 44 commits into from

Conversation

alex-page
Copy link
Member

@alex-page alex-page commented Jun 17, 2019

WHY are these changes introduced?

Fixes #1673

WHAT is this pull request doing?

Using mutation observer so that the resize calculation is being run at the correct time. It is also resetting the left value to 0 which is needed for the recalc.

How to 🎩

🖥 Local development instructions
🗒 General tophatting guidelines
📄 Changelog guidelines

This needs to be tested in web and in Polaris with around 6-7 menu items.

Copy-paste this code in playground/Playground.tsx:
import * as React from 'react';
import {ArrowLeftMinor} from '@shopify/polaris-icons';
import {string} from 'prop-types';
import {
  AppProvider,
  Frame,
  Page,
  Card,
  ActionList,
  TopBar,
  Button,
  Popover,
  PopoverProps,
} from '../src';

interface State {
  userMenuOpen: boolean;
  searchActive: boolean;
  searchText: string;
  popover1Active: boolean;
  popover2Active: boolean;
  popover3Active: boolean;
  popover1PositionBelow: boolean;
  popover2PositionBelow: boolean;
  popover3PositionBelow: boolean;
  showScrollingUserMenu: boolean;
}

export class Playground extends React.Component {
  state: State = {
    userMenuOpen: false,
    searchActive: false,
    searchText: '',
    popover1Active: false,
    popover2Active: false,
    popover3Active: false,
    popover1PositionBelow: true,
    popover2PositionBelow: true,
    popover3PositionBelow: true,
    showScrollingUserMenu: true,
  };

  render() {
    const {
      state,
      handleSearchChange,
      handleSearchResultsDismiss,
      toggleUserMenu,
    } = this;
    const {
      userMenuOpen,
      searchText,
      searchActive,
      showScrollingUserMenu,
    } = state;

    const theme = {
      colors: {
        topBar: {
          background: '#357997',
          backgroundLighter: '#6192a9',
          color: '#FFFFFF',
        },
      },
      logo: {
        width: 124,
        topBarSource:
          'https://cdn.shopify.com/s/files/1/0446/6937/files/jaded-pixel-logo-color.svg?6215648040070010999',
        url: 'http://jadedpixel.com',
        accessibilityLabel: 'Jaded Pixel',
      },
    };

    const actionsWithScroll = [
      {
        items: [{content: 'Back to Shopify', icon: ArrowLeftMinor}],
      },
      {
        items: [{content: 'Community forums'}],
      },
      {
        items: [{content: 'Community forums'}],
      },
      {
        items: [{content: 'Community forums'}],
      },
      {
        items: [{content: 'Community forums'}],
      },
      {
        items: [{content: 'Community forums'}],
      },
      {
        items: [{content: 'Community forums'}],
      },
    ];

    const actions = [
      {
        items: [{content: 'Back to Shopify', icon: ArrowLeftMinor}],
      },
      {
        items: [{content: 'Community forums'}],
      },
      {
        items: [{content: 'Community forums'}],
      },
      {
        items: [{content: 'Community forums'}],
      },
    ];

    const userMenuMarkup = (
      <TopBar.UserMenu
        actions={showScrollingUserMenu ? actionsWithScroll : actions}
        name="Dharma"
        detail="Jaded Pixel"
        initials="D"
        open={userMenuOpen}
        onToggle={toggleUserMenu}
      />
    );

    const searchResultsMarkup = (
      <Card>
        <ActionList
          items={[
            {content: 'Shopify help center'},
            {content: 'Community forums'},
          ]}
        />
      </Card>
    );

    const searchFieldMarkup = (
      <TopBar.SearchField
        onChange={handleSearchChange}
        value={searchText}
        placeholder="Search"
      />
    );

    const topBarMarkup = (
      <TopBar
        showNavigationToggle
        userMenu={userMenuMarkup}
        searchResultsVisible={searchActive}
        searchField={searchFieldMarkup}
        searchResults={searchResultsMarkup}
        onSearchResultsDismiss={handleSearchResultsDismiss}
      />
    );

    const activator1 = (
      <Button onClick={this.togglePopover('popover1', 'Active')}>
        Popover Left
      </Button>
    );

    const activator2 = (
      <Button onClick={this.togglePopover('popover2', 'Active')}>
        Popover Center
      </Button>
    );

    const activator3 = (
      <Button onClick={this.togglePopover('popover3', 'Active')}>
        Popover Right
      </Button>
    );

    return (
      <AppProvider i18n={{}} theme={theme}>
        <Frame topBar={topBarMarkup}>
          <Page
            title="Popover alignment/width bug"
            primaryAction={{
              content: `Render ${
                showScrollingUserMenu ? 'non-scrolling' : 'scrolling'
              } user menu`,
              onAction: this.toggleScrollingUserMenu,
            }}
          >
            <Card>
              <Card.Section
                actions={[
                  {
                    content: 'Toggle position',
                    onAction: this.togglePopover('popover1', 'PositionBelow'),
                  },
                ]}
              >
                <Popover
                  active={this.state.popover1Active}
                  activator={activator1}
                  onClose={this.togglePopover('popover1', 'Active')}
                  preferredAlignment="left"
                  preferredPosition={
                    this.state.popover1PositionBelow ? 'below' : 'above'
                  }
                >
                  <ActionList
                    items={[{content: 'Import'}, {content: 'Export'}]}
                  />
                </Popover>
              </Card.Section>
              <Card.Section
                actions={[
                  {
                    content: 'Toggle position',
                    onAction: this.togglePopover('popover2', 'PositionBelow'),
                  },
                ]}
              >
                <Popover
                  active={this.state.popover2Active}
                  activator={activator2}
                  onClose={this.togglePopover('popover2', 'Active')}
                  preferredAlignment="center"
                  preferredPosition={
                    this.state.popover2PositionBelow ? 'below' : 'above'
                  }
                >
                  <ActionList
                    items={[{content: 'Import'}, {content: 'Export'}]}
                  />
                </Popover>
              </Card.Section>
              <Card.Section
                actions={[
                  {
                    content: 'Toggle position',
                    onAction: this.togglePopover('popover3', 'PositionBelow'),
                  },
                ]}
              >
                <Popover
                  active={this.state.popover3Active}
                  activator={activator3}
                  onClose={this.togglePopover('popover3', 'Active')}
                  preferredAlignment="right"
                  preferredPosition={
                    this.state.popover3PositionBelow ? 'below' : 'above'
                  }
                >
                  <ActionList
                    items={[{content: 'Import'}, {content: 'Export'}]}
                  />
                </Popover>
              </Card.Section>
            </Card>
          </Page>
        </Frame>
      </AppProvider>
    );
  }

  toggleUserMenu = () => {
    this.setState(({userMenuOpen}: State) => ({userMenuOpen: !userMenuOpen}));
  };

  toggleScrollingUserMenu = () => {
    this.setState(({showScrollingUserMenu, userMenuOpen}: State) => ({
      showScrollingUserMenu: !showScrollingUserMenu,
    }));
  };

  togglePopover = (popoverID: string, prop: string) => () => {
    this.setState((state: State) => {
      return {[`${popoverID}${prop}`]: !state[`${popoverID}${prop}`]};
    });
  };

  handleSearchResultsDismiss = () => {
    this.setState(() => {
      return {
        searchActive: false,
        searchText: '',
      };
    });
  };

  handleSearchChange = (value) => {
    this.setState({searchText: value});
    if (value.length > 0) {
      this.setState({searchActive: true});
    } else {
      this.setState({searchActive: false});
    }
  };
}

🎩 checklist

@alex-page alex-page self-assigned this Jun 17, 2019
@BPScott BPScott temporarily deployed to polaris-react-pr-1692 June 17, 2019 17:02 Inactive
@alex-page alex-page changed the title Fix PositionOverlay width issue for the menu Fix PositionOverlay width issue for the menu in TopBar Jun 17, 2019
@alex-page
Copy link
Member Author

@ken3650 I have added as a reviewer on this PR as it reverts some of the changes you made in #1382

@AndrewMusgrave I have added you as a reviewer as it uses your mutation observer code.

@alex-page alex-page added Bug Something is broken and not working as intended in the system. 🌟High Priority labels Jun 17, 2019
@BPScott BPScott temporarily deployed to polaris-react-pr-1692 June 17, 2019 17:43 Inactive
@BPScott BPScott temporarily deployed to polaris-react-pr-1692 June 17, 2019 17:45 Inactive
@danrosenthal
Copy link
Contributor

Can you or @AndrewMusgrave explain about MutationObserver?

@AndrewMusgrave
Copy link
Member

@danrosenthal #1621

If the change is needed for this, I'm tempted to cherry pick the commit into v3

@danrosenthal
Copy link
Contributor

If the change is needed for this, I'm tempted to cherry pick the commit into v3

Seems like it is.

@BPScott BPScott temporarily deployed to polaris-react-pr-1692 June 18, 2019 13:01 Inactive
@BPScott BPScott temporarily deployed to polaris-react-pr-1692 June 18, 2019 13:02 Inactive
@alex-page
Copy link
Member Author

alex-page commented Jun 18, 2019

It's not "needed" but it made debugging and performance of the component a lot better. @AndrewMusgrave please cherry pick.

@BPScott BPScott temporarily deployed to polaris-react-pr-1692 June 18, 2019 13:27 Inactive
@danrosenthal
Copy link
Contributor

Looks like total code coverage could be achieved with a couple testing tweaks

👀
Screen Shot 2019-06-18 at 9 57 00 AM

Testing it additionally by making fixed false ought to get us to 90%. Would it also be possible to not have an overlay in one of the tests?

Copy link
Contributor

@ken3650 ken3650 left a comment

Choose a reason for hiding this comment

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

Can't speak to all the changes, but 🎩'ed the change against my earlier issue that this changes and all is good 👍

@AndrewMusgrave
Copy link
Member

Would it also be possible to not have an overlay in one of the tests?

Nope since the code will never run before componentDidMount 😬

@BPScott BPScott temporarily deployed to polaris-react-pr-1692 June 18, 2019 18:45 Inactive
@BPScott BPScott temporarily deployed to polaris-react-pr-1692 June 18, 2019 18:47 Inactive
@alex-page
Copy link
Member Author

This isn't fixed 😭 the issue still exists

@alex-page alex-page assigned chloerice and unassigned alex-page Jun 24, 2019
@chloerice
Copy link
Member

chloerice commented Jul 12, 2019

Quick update:

I've been trying to narrow down the reason this is an issue, and it seems to only be reproducible with the UserMenu. My changes include:

  • Handling UserMenu spacing in its parent

    • Currently, its handling its own margin-right, which is causing the overlay to be positioned up against the far right since its activator's width was including the margin on its wrapper.
  • Explicitly setting the UserMenu Popover, rendered by the Menu subcomponent, to have a preferredPosition of right

    • Currently, no preferred position was specified, so the calculation for center aligned aligned popover was being returned because the conditional inside of calculateHorizontalPosition wasn't being satisfied.
  • Calculating and setting right to horizontally position the overlay when preferredAlignment="right" instead calculating and setting left

Unfortunately, while I thought I'd fixed this, in spite of these changes the bug is still present in Firefox and Safari and only fixed in Chrome 😞

@github-actions
Copy link
Contributor

github-actions bot commented Oct 3, 2019

Results

💦 Potential splash zone of changes introduced to src/**/*.tsx in this pull request:

Files modified9
Files potentially affected29

Details

All files potentially affected (total: 29)
.eslintignore (total: 0)

Files potentially affected (total: 0)

UNRELEASED.md (total: 0)

Files potentially affected (total: 0)

🎨 src/components/Popover/Popover.scss (total: 25)

Files potentially affected (total: 25)

🧩 src/components/PositionedOverlay/PositionedOverlay.tsx (total: 28)

Files potentially affected (total: 28)

🧩 src/components/PositionedOverlay/utilities/math.ts (total: 29)

Files potentially affected (total: 29)

🎨 src/components/TopBar/TopBar.scss (total: 1)

Files potentially affected (total: 1)

🎨 src/components/TopBar/components/Menu/Menu.scss (total: 3)

Files potentially affected (total: 3)

🧩 src/components/TopBar/components/Menu/Menu.tsx (total: 2)

Files potentially affected (total: 2)

🧩 src/components/TopBar/components/UserMenu/UserMenu.tsx (total: 1)

Files potentially affected (total: 1)


This comment automatically updates as changes are made to this pull request.
Feedback, troubleshooting: open an issue or reach out on Slack in #polaris-tooling.

@alex-page
Copy link
Member Author

alex-page commented Oct 3, 2019

Replaced with new PR #2231

@alex-page alex-page closed this Oct 3, 2019
@alex-page alex-page deleted the overlay-width branch October 25, 2019 15:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Something is broken and not working as intended in the system.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

PositionOverlay incorrectly calculating the left value for right aligned components with scroll bars
7 participants