Skip to content

Conversation

dleroux
Copy link
Contributor

@dleroux dleroux commented Nov 15, 2018

WHY are these changes introduced?

Bulk actions at the top of the Resource List should stick to the viewport top until the bottom of the list is reached. Currently there's a bug where the Bulk Actions never stop sticking. This is due to the component rendering before the List ref is resolved.

WHAT is this pull request doing?

Ensure the List Ref is available before rendering the list.

Before:

stickybroken

After:

stickyfixed

How to 🎩

Copy-paste this code in playground/Playground.tsx:
/* eslint-disable */

import * as React from 'react';
import {
  Page,
  ResourceList,
  Card,
  AppliedFilter,
  FilterType,
  AppProvider,
  Sticky,
} from '@shopify/polaris';
import {autobind} from '@shopify/javascript-utilities/decorators';

const items: any[] = [
  {
    onClick: true,
    url: 'https://www.google.com',
    actions: [{content: 'View listing', url: 'http://www.facebook.com'}],
    title: 'Has url, onClick, and actions',
  },
  {
    onClick: false,
    url: 'https://www.google.com',
    actions: [{content: 'View listing', url: 'http://www.facebook.com'}],
    title: 'Has url, and actions',
  },
  {
    onClick: true,
    actions: [{content: 'View listing', url: 'http://www.facebook.com'}],
    title: 'Has onClick, and actions',
  },
  {
    onClick: false,
    url: 'https://www.google.com',
    title: 'Has url',
  },
  {
    onClick: true,
    title: 'Has onClick',
  },
  {
    onClick: true,
    url: 'https://www.google.com',
    actions: [{content: 'View listing', url: 'http://www.facebook.com'}],
    title: 'Has url, onClick, and actions',
  },
  {
    onClick: false,
    url: 'https://www.google.com',
    actions: [{content: 'View listing', url: 'http://www.facebook.com'}],
    title: 'Has url, and actions',
  },
  {
    onClick: true,
    actions: [{content: 'View listing', url: 'http://www.facebook.com'}],
    title: 'Has onClick, and actions',
  },
  {
    onClick: false,
    url: 'https://www.google.com',
    title: 'Has url',
  },
  {
    onClick: true,
    title: 'Has onClick',
  },
  {
    onClick: true,
    url: 'https://www.google.com',
    actions: [{content: 'View listing', url: 'http://www.facebook.com'}],
    title: 'Has url, onClick, and actions',
  },
  {
    onClick: false,
    url: 'https://www.google.com',
    actions: [{content: 'View listing', url: 'http://www.facebook.com'}],
    title: 'Has url, and actions',
  },
  {
    onClick: true,
    actions: [{content: 'View listing', url: 'http://www.facebook.com'}],
    title: 'Has onClick, and actions',
  },
  {
    onClick: false,
    url: 'https://www.google.com',
    title: 'Has url',
  },
  {
    onClick: true,
    title: 'Has onClick',
  },
];

const mockFilters: any[] = [
  {
    key: 'filterKey1',
    label: 'Product type',
    operatorText: 'is',
    type: FilterType.Select,
    options: [
      'Bundle',
      {
        value: 'electronic_value',
        label: 'Electronic',
        disabled: true,
      },
      {
        value: 'beauty_value',
        label: 'Beauty',
      },
    ],
  },
  {
    key: 'filterKey2',
    label: 'Tagged with',
    type: FilterType.TextField,
  },
];

const mockAppliedFilters = [
  {
    key: 'filterKey1',
    value: 'Bundle',
  },
  {
    key: 'filterKey1',
    value: 'beauty_value',
  },
  {
    key: 'filterKey1',
    value: 'Not a option value',
  },
  {
    key: 'filterKey2',
    value: 'New Tag Name',
  },
  {
    key: 'filterKey3',
    value: 'This filter does not exist',
  },
];

const mockSortOptions = [
  'Product title (A-Z)',
  {
    value: 'PRODUCT_TITLE_DESC',
    label: 'Product title (Z-A)',
  },
  {
    value: 'EXTRA',
    label: 'Disabled Option',
    disabled: true,
  },
];

interface State {
  searchValue?: string;
  filterSearchFocused: boolean;
  appliedFilters: AppliedFilter[];
  selectedItems: string[] | 'All';
  sortValue?: string;
}

export default class Playground extends React.Component<never, State> {
  state: State = {
    selectedItems: [],
    filterSearchFocused: false,
    appliedFilters: mockAppliedFilters,
  };

  render() {
    const {searchValue, appliedFilters} = this.state;

    const resourceName = {
      singular: 'Product',
      plural: 'Products',
    };

    return (
      <AppProvider>
        <div>
          <div style={{position: 'relative', zIndex: 1000}}>
            <Sticky>
              <div
                style={{
                  height: '100px',
                  width: '100%',
                  backgroundColor: 'pink',
                  zIndex: 1000,
                }}
              />
            </Sticky>
          </div>
          <Page title="Playground">
            {/* <Scrollable style={{height: '500px'}}> */}
            <Card>
              <ResourceList
                resourceName={resourceName}
                items={items}
                renderItem={handleRenderItem}
                hasMoreItems
                filterControl={
                  <ResourceList.FilterControl
                    searchValue={searchValue}
                    onSearchChange={this.handleSearchChange}
                    additionalAction={{
                      content: 'Save',
                    }}
                    filters={mockFilters}
                    appliedFilters={appliedFilters}
                    onFiltersChange={this.handleFilterChange}
                  />
                }
                selectedItems={this.state.selectedItems}
                onSelectionChange={this.handleSelectionChange}
                promotedBulkActions={[
                  {
                    content: 'Really long text on button 1',
                    onAction: this.bulkActionOne,
                  },
                  {
                    content: 'long text button 2',
                    disabled: true,
                    url: 'http://www.google.com',
                  },
                ]}
                bulkActions={[
                  {
                    content: 'button 3',
                    onAction: this.bulkActionThree,
                  },
                  {
                    content: 'button 4',
                    onAction: this.bulkActionFour,
                  },
                  {
                    content: 'button 5',
                    onAction: this.bulkActionFive,
                    disabled: true,
                  },
                ]}
                sortValue={this.state.sortValue}
                sortOptions={mockSortOptions}
                onSortChange={this.handleSortChange}
              />
              <br />
              <br />
              <ResourceList
                resourceName={resourceName}
                items={items}
                renderItem={handleRenderItem}
                hasMoreItems
                filterControl={
                  <ResourceList.FilterControl
                    searchValue={searchValue}
                    onSearchChange={this.handleSearchChange}
                    additionalAction={{
                      content: 'Save',
                    }}
                    filters={mockFilters}
                    appliedFilters={appliedFilters}
                    onFiltersChange={this.handleFilterChange}
                  />
                }
                selectedItems={this.state.selectedItems}
                onSelectionChange={this.handleSelectionChange}
                promotedBulkActions={[
                  {
                    content: 'Really long text on button 1',
                    onAction: this.bulkActionOne,
                  },
                  {
                    content: 'long text button 2',
                    disabled: true,
                    url: 'http://www.google.com',
                  },
                ]}
                bulkActions={[
                  {
                    content: 'button 3',
                    onAction: this.bulkActionThree,
                  },
                  {
                    content: 'button 4',
                    onAction: this.bulkActionFour,
                  },
                  {
                    content: 'button 5',
                    onAction: this.bulkActionFive,
                    disabled: true,
                  },
                ]}
                sortValue={this.state.sortValue}
                sortOptions={mockSortOptions}
                onSortChange={this.handleSortChange}
              />
            </Card>
            {/* </Scrollable> */}
          </Page>
        </div>
      </AppProvider>
    );
  }

  @autobind
  private handleSelectionChange(selectedItems: string[]) {
    this.setState({selectedItems});
  }

  @autobind
  private handleSearchChange(searchValue: string) {
    this.setState({searchValue});
  }

  @autobind
  private handleFilterChange(appliedFilters: AppliedFilter[]) {
    this.setState({appliedFilters});
  }

  @autobind
  private handleSortChange(sortValue: string) {
    this.setState({sortValue});
  }

  @autobind
  private bulkActionOne() {
    console.log('Clicked on bulk action one.');
  }

  @autobind
  private bulkActionTwo() {
    console.log('Clicked on bulk action two.');
  }

  @autobind
  private bulkActionThree() {
    console.log('Clicked on bulk action three.');
  }

  @autobind
  private bulkActionFour() {
    console.log('Clicked on bulk action four.');
  }

  @autobind
  private bulkActionFive() {
    console.log('Clicked on bulk action five.');
  }
}

function handleRenderItem(item: any, id: any) {
  return (
    <ResourceList.Item
      id={id}
      url={item.url}
      shortcutActions={item.actions}
      accessibilityLabel={`View details for ${item.title}`}
    >
      <div>Item {id}</div>
      <div>{item.title}</div>
    </ResourceList.Item>
  );
}

/* eslint-enable */

🎩 checklist

@BPScott BPScott temporarily deployed to polaris-react-pr-627 November 15, 2018 20:46 Inactive
@BPScott BPScott temporarily deployed to polaris-react-pr-627 November 15, 2018 20:51 Inactive
@dleroux dleroux changed the title [WIP] [Resource List] Fixing Bulk Actions that don't stock sticking [Resource List] Fixing Bulk Actions that don't stock sticking Nov 15, 2018
{sortingSelectMarkup}
{selectButtonMarkup}
const headerMarkup = (showHeader || needsHeader) &&
listNode && (
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Simply brought back this listNode check before rendering the list header.

Copy link

@danrosenthal danrosenthal left a comment

Choose a reason for hiding this comment

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

🎩

@dleroux dleroux force-pushed the fixing-sticky-bulkactions branch from 251cc37 to 1e49be8 Compare November 16, 2018 19:04
@BPScott BPScott temporarily deployed to polaris-react-pr-627 November 16, 2018 19:04 Inactive
@dleroux dleroux merged commit a3bebe4 into master Nov 16, 2018
@danrosenthal danrosenthal temporarily deployed to production November 16, 2018 21:41 Inactive
@kaelig kaelig deleted the fixing-sticky-bulkactions branch December 10, 2018 23:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants