From c7b24b8243696e089ff3cddceb1e1bde300e1651 Mon Sep 17 00:00:00 2001 From: Marc Thomas Date: Wed, 28 Sep 2022 11:32:20 +0100 Subject: [PATCH 01/32] chore: Add in SelectAllActions and update BulkActions chore: begin tests chore: remove icons --- .../components/BulkActions/BulkActions.scss | 44 ++- .../components/BulkActions/BulkActions.tsx | 270 +++--------------- .../BulkActions/tests/BulkActions.test.tsx | 225 +-------------- .../CheckableButton/CheckableButton.scss | 8 + .../CheckableButton/CheckableButton.tsx | 19 +- .../src/components/IndexTable/IndexTable.scss | 25 +- .../IndexTable/IndexTable.stories.tsx | 40 ++- .../src/components/IndexTable/IndexTable.tsx | 59 ++-- .../IndexTable/tests/IndexTable.test.tsx | 9 +- .../components/ResourceList/ResourceList.scss | 22 ++ .../ResourceList/ResourceList.stories.tsx | 75 +++++ .../components/ResourceList/ResourceList.tsx | 48 +++- .../ResourceList/tests/ResourceList.test.tsx | 61 ++-- .../SelectAllActions/SelectAllActions.scss | 22 ++ .../SelectAllActions/SelectAllActions.tsx | 96 +++++++ .../src/components/SelectAllActions/index.ts | 1 + .../tests/SelectAllActions.test.tsx | 230 +++++++++++++++ polaris-react/src/components/index.ts | 1 + .../src/utilities/resource-list/types.ts | 2 +- 19 files changed, 692 insertions(+), 565 deletions(-) create mode 100644 polaris-react/src/components/SelectAllActions/SelectAllActions.scss create mode 100644 polaris-react/src/components/SelectAllActions/SelectAllActions.tsx create mode 100644 polaris-react/src/components/SelectAllActions/index.ts create mode 100644 polaris-react/src/components/SelectAllActions/tests/SelectAllActions.test.tsx create mode 100644 polaris-react/src/components/index.ts diff --git a/polaris-react/src/components/BulkActions/BulkActions.scss b/polaris-react/src/components/BulkActions/BulkActions.scss index c0ee4ef6f1e..e4ab75cc559 100644 --- a/polaris-react/src/components/BulkActions/BulkActions.scss +++ b/polaris-react/src/components/BulkActions/BulkActions.scss @@ -7,11 +7,25 @@ $bulk-actions-button-stacking-order: ( .Group { @include text-style-input; - width: 100%; display: none; align-items: center; flex-wrap: wrap; opacity: 0; + width: 90vw; + justify-content: center; + + @media #{$p-breakpoints-sm-up} { + display: flex; + + &.Group-exiting { + transition: none; + } + + &.Group-exited { + opacity: 0; + display: none; + } + } &.Group-measuring { transition: none; @@ -36,29 +50,6 @@ $bulk-actions-button-stacking-order: ( display: none; } -.Group-smallScreen { - @media #{$p-breakpoints-sm-up} { - display: none; - } -} - -.Group-largeScreen { - display: none; - - @media #{$p-breakpoints-sm-up} { - display: flex; - - &.Group-exiting { - transition: none; - } - - &.Group-exited { - opacity: 0; - display: none; - } - } -} - .ButtonGroupWrapper { width: 100%; max-width: 100%; @@ -74,7 +65,10 @@ $bulk-actions-button-stacking-order: ( @media #{$p-breakpoints-sm-up} { width: auto; justify-content: flex-start; - margin-right: var(--p-space-2); + padding: var(--p-space-4); + background: var(--p-surface); + border-radius: var(--p-border-radius-2); + box-shadow: var(--p-shadow-popover); } .Group-measuring & { diff --git a/polaris-react/src/components/BulkActions/BulkActions.tsx b/polaris-react/src/components/BulkActions/BulkActions.tsx index 0e603e5c19f..049c447c6d2 100644 --- a/polaris-react/src/components/BulkActions/BulkActions.tsx +++ b/polaris-react/src/components/BulkActions/BulkActions.tsx @@ -1,6 +1,5 @@ import React, {PureComponent, createRef} from 'react'; -import {CSSTransition, Transition} from 'react-transition-group'; -import {motion} from '@shopify/polaris-tokens'; +import {Transition} from 'react-transition-group'; import {debounce} from '../../utilities/debounce'; import {classNames} from '../../utilities/css'; @@ -9,15 +8,12 @@ import {clamp} from '../../utilities/clamp'; import type { BadgeAction, DisableableAction, - Action, ActionListSection, MenuGroupDescriptor, } from '../../types'; import {ActionList} from '../ActionList'; import {Popover} from '../Popover'; -import {Button} from '../Button'; import {ButtonGroup} from '../ButtonGroup'; -import {CheckableButton} from '../CheckableButton'; // eslint-disable-next-line import/no-deprecated import {EventListener} from '../EventListener'; @@ -33,28 +29,14 @@ type TransitionStatus = 'entering' | 'entered' | 'exiting' | 'exited'; const MAX_PROMOTED_ACTIONS = 2; export interface BulkActionsProps { - /** Visually hidden text for screen readers */ - accessibilityLabel?: string; - /** Whether to render the small screen BulkActions or not */ - smallScreen?: boolean; - /** Label for the bulk actions */ - label?: string; - /** State of the bulk actions checkbox */ - selected?: boolean | 'indeterminate'; /** List is in a selectable state */ selectMode?: boolean; /** Actions that will be given more prominence */ promotedActions?: (BulkAction | MenuGroupDescriptor)[]; /** List of actions */ actions?: (BulkAction | BulkActionListSection)[]; - /** Text to select all across pages */ - paginatedSelectAllText?: string; - /** Action for selecting all across pages */ - paginatedSelectAllAction?: Action; /** Disables bulk actions */ disabled?: boolean; - /** Callback when the select all checkbox is clicked */ - onToggleAll?(): void; /** Callback when selectable state of list is changed */ onSelectModeToggle?(selectMode: boolean): void; /** Callback when more actions button is toggled */ @@ -66,41 +48,29 @@ type CombinedProps = BulkActionsProps & { }; interface State { - smallScreenPopoverVisible: boolean; - largeScreenPopoverVisible: boolean; + popoverVisible: boolean; containerWidth: number; measuring: boolean; } -const slideClasses = { - appear: classNames(styles.Slide, styles['Slide-appear']), - appearActive: classNames(styles.Slide, styles['Slide-appearing']), - enter: classNames(styles.Slide, styles['Slide-enter']), - enterActive: classNames(styles.Slide, styles['Slide-entering']), - exit: classNames(styles.Slide, styles['Slide-exit']), -}; - class BulkActionsInner extends PureComponent { state: State = { - smallScreenPopoverVisible: false, - largeScreenPopoverVisible: false, + popoverVisible: false, containerWidth: 0, measuring: true, }; private containerNode: HTMLElement | null = null; - private largeScreenButtonsNode: HTMLElement | null = null; + private buttonsNode: HTMLElement | null = null; private moreActionsNode: HTMLElement | null = null; - private checkableWrapperNode = createRef(); - private largeScreenGroupNode = createRef(); - private smallScreenGroupNode = createRef(); + private groupNode = createRef(); private promotedActionsWidths: number[] = []; private bulkActionsWidth = 0; private addedMoreActionsWidthForMeasuring = 0; private handleResize = debounce( () => { - const {smallScreenPopoverVisible, largeScreenPopoverVisible} = this.state; + const {popoverVisible} = this.state; if (this.containerNode) { const containerWidth = this.containerNode.getBoundingClientRect().width; @@ -109,10 +79,9 @@ class BulkActionsInner extends PureComponent { } } - if (smallScreenPopoverVisible || largeScreenPopoverVisible) { + if (popoverVisible) { this.setState({ - smallScreenPopoverVisible: false, - largeScreenPopoverVisible: false, + popoverVisible: false, }); } }, @@ -152,14 +121,6 @@ class BulkActionsInner extends PureComponent { return clamp(counter, 0, promotedActions.length); } - private hasActions() { - const {promotedActions, actions} = this.props; - return Boolean( - (promotedActions && promotedActions.length > 0) || - (actions && actions.length > 0), - ); - } - private actionSections(): BulkActionListSection[] | undefined { const {actions} = this.props; @@ -212,8 +173,8 @@ class BulkActionsInner extends PureComponent { this.moreActionsNode.getBoundingClientRect().width; } - this.bulkActionsWidth = this.largeScreenButtonsNode - ? this.largeScreenButtonsNode.getBoundingClientRect().width - + this.bulkActionsWidth = this.buttonsNode + ? this.buttonsNode.getBoundingClientRect().width - this.addedMoreActionsWidthForMeasuring : 0; @@ -227,19 +188,7 @@ class BulkActionsInner extends PureComponent { // eslint-disable-next-line @typescript-eslint/member-ordering render() { - const { - selectMode, - accessibilityLabel, - label = '', - onToggleAll, - selected, - smallScreen, - disabled, - promotedActions, - paginatedSelectAllText = null, - paginatedSelectAllAction, - i18n, - } = this.props; + const {selectMode, disabled, promotedActions, i18n} = this.props; const actionSections = this.actionSections(); @@ -256,71 +205,11 @@ class BulkActionsInner extends PureComponent { ); } - const {smallScreenPopoverVisible, largeScreenPopoverVisible, measuring} = - this.state; - - const paginatedSelectAllActionMarkup = paginatedSelectAllAction ? ( - - ) : null; - - const paginatedSelectAllTextMarkup = - paginatedSelectAllText && paginatedSelectAllAction ? ( - {paginatedSelectAllText} - ) : ( - paginatedSelectAllText - ); - - const paginatedSelectAllMarkup = - paginatedSelectAllActionMarkup || paginatedSelectAllTextMarkup ? ( -
- {paginatedSelectAllTextMarkup} {paginatedSelectAllActionMarkup} -
- ) : null; - - const cancelButton = ( - - ); + const {popoverVisible, measuring} = this.state; const numberOfPromotedActionsToRender = this.numberOfPromotedActionsToRender(); - const allActionsPopover = this.hasActions() ? ( -
- - } - onClose={this.toggleSmallScreenPopover} - > - - -
- ) : null; - const promotedActionsMarkup = promotedActions && numberOfPromotedActionsToRender > 0 ? [...promotedActions] @@ -372,131 +261,67 @@ class BulkActionsInner extends PureComponent { actionSections || rolledInPromotedActions.length > 0 || measuring ? (
} - onClose={this.toggleLargeScreenPopover} + onClose={this.togglePopover} >
) : null; - const checkableButtonProps = { - accessibilityLabel, - label, - selected, - selectMode, - onToggleAll, - measuring, - disabled, - }; - - const smallScreenGroup = smallScreen ? ( - - {(status: TransitionStatus) => { - const smallScreenGroupClassName = classNames( - styles.Group, - styles['Group-smallScreen'], - styles[`Group-${status}`], - ); - return ( -
-
- - -
- -
-
- {allActionsPopover} - {cancelButton} -
-
- {paginatedSelectAllMarkup} -
- ); - }} -
- ) : null; - - const largeGroupContent = + const groupContent = promotedActionsMarkup || actionsPopover ? ( - - + {promotedActionsMarkup} {actionsPopover} - ) : ( - - ); + ) : null; - const largeScreenGroup = smallScreen ? null : ( + if (!groupContent) { + return null; + } + + const group = ( {(status: TransitionStatus) => { - const largeScreenGroupClassName = classNames( + const groupClassName = classNames( styles.Group, - styles['Group-largeScreen'], !measuring && styles[`Group-${status}`], measuring && styles['Group-measuring'], ); return ( -
+
- {largeGroupContent} + {groupContent}
- {paginatedSelectAllMarkup}
); }} ); - return ( -
- {smallScreenGroup} - {largeScreenGroup} -
- ); + return
{group}
; } private isNewBadgeInBadgeActions() { @@ -512,8 +337,8 @@ class BulkActionsInner extends PureComponent { return false; } - private setLargeScreenButtonsNode = (node: HTMLElement | null) => { - this.largeScreenButtonsNode = node; + private setButtonsNode = (node: HTMLElement | null) => { + this.buttonsNode = node; }; private setContainerNode = (node: HTMLElement | null) => { @@ -524,34 +349,13 @@ class BulkActionsInner extends PureComponent { this.moreActionsNode = node; }; - private setSelectMode = (val: boolean) => { - const {onSelectModeToggle} = this.props; - if (onSelectModeToggle) { - onSelectModeToggle(val); - } - }; - - private toggleSmallScreenPopover = () => { + private togglePopover = () => { if (this.props.onMoreActionPopoverToggle) { - this.props.onMoreActionPopoverToggle( - this.state.smallScreenPopoverVisible, - ); - } - - this.setState(({smallScreenPopoverVisible}) => ({ - smallScreenPopoverVisible: !smallScreenPopoverVisible, - })); - }; - - private toggleLargeScreenPopover = () => { - if (this.props.onMoreActionPopoverToggle) { - this.props.onMoreActionPopoverToggle( - this.state.largeScreenPopoverVisible, - ); + this.props.onMoreActionPopoverToggle(this.state.popoverVisible); } - this.setState(({largeScreenPopoverVisible}) => ({ - largeScreenPopoverVisible: !largeScreenPopoverVisible, + this.setState(({popoverVisible}) => ({ + popoverVisible: !popoverVisible, })); }; diff --git a/polaris-react/src/components/BulkActions/tests/BulkActions.test.tsx b/polaris-react/src/components/BulkActions/tests/BulkActions.test.tsx index af0225256d3..d63465fde21 100644 --- a/polaris-react/src/components/BulkActions/tests/BulkActions.test.tsx +++ b/polaris-react/src/components/BulkActions/tests/BulkActions.test.tsx @@ -3,9 +3,6 @@ import {Transition, CSSTransition} from 'react-transition-group'; import {mountWithApp} from 'tests/utilities'; import {ActionList} from '../../ActionList'; -import {CheckableButton} from '../../CheckableButton'; -import {Button} from '../../Button'; -import {Popover} from '../../Popover'; import { BulkActionButton, BulkActionMenu, @@ -17,10 +14,6 @@ import styles from '../BulkActions.scss'; interface Props { bulkActions: BulkActionButtonProps['content'][]; promotedActions: NonNullable; - paginatedSelectAllText: string; - selected: boolean; - accessibilityLabel: string; - label: string; disabled: boolean; } @@ -34,10 +27,6 @@ const bulkActionProps: Props = { content: 'button 2', }, ], - paginatedSelectAllText: 'paginated select all text string', - selected: false, - accessibilityLabel: 'test-aria-label', - label: 'Test-Label', disabled: false, }; @@ -106,13 +95,6 @@ describe('', () => { expect(bulkActionsCount).toBe(0); }); - - it('renders a Popover when smallScreen is true', () => { - const bulkActionsElement = mountWithApp( - , - ); - expect(bulkActionsElement).toContainReactComponentTimes(Popover, 1); - }); }); describe('loading', () => { @@ -125,90 +107,17 @@ describe('', () => { content: 'button 1', }, ]} - paginatedSelectAllAction={{content: 'content', onAction: () => {}}} disabled />, ); - expect(bulkActionsElement).toContainReactComponentTimes('button', 2, { + expect(bulkActionsElement).toContainReactComponentTimes('button', 1, { 'aria-disabled': true, }); }); }); describe('props', () => { - describe('accessibilityLabel', () => { - it('is passed down to CheckableButton', () => { - const {accessibilityLabel} = bulkActionProps; - const bulkActions = mountWithApp(); - const checkableButtonLength = - bulkActions.findAll(CheckableButton).length; - - expect(bulkActions).toContainReactComponentTimes( - CheckableButton, - checkableButtonLength, - { - accessibilityLabel, - }, - ); - }); - - it('does not pass down to CheckableButton when the property is not provided', () => { - const {accessibilityLabel, ...props} = bulkActionProps; - const bulkActions = mountWithApp(); - - expect(bulkActions).toContainReactComponentTimes(CheckableButton, 0, { - accessibilityLabel, - }); - }); - }); - - describe('label', () => { - it('is passed down to CheckableButton', () => { - const {label} = bulkActionProps; - const bulkActions = mountWithApp(); - const checkableButtonLength = - bulkActions.findAll(CheckableButton).length; - expect(bulkActions).toContainReactComponentTimes( - CheckableButton, - checkableButtonLength, - {label}, - ); - }); - - it('does not pass down to CheckableButton when the property is not provided', () => { - const {label, ...props} = bulkActionProps; - const bulkActions = mountWithApp(); - expect(bulkActions).toContainReactComponentTimes(CheckableButton, 0, { - label, - }); - }); - }); - - describe('selected', () => { - it('is passed down to CheckableButton', () => { - const {selected} = bulkActionProps; - const bulkActions = mountWithApp(); - const checkableButtonLength = - bulkActions.findAll(CheckableButton).length; - - expect(bulkActions).toContainReactComponentTimes( - CheckableButton, - checkableButtonLength, - {selected}, - ); - }); - - it('does not pass down to CheckableButton when the property is not provided', () => { - const {selected, ...props} = bulkActionProps; - const bulkActions = mountWithApp(); - - expect(bulkActions).toContainReactComponentTimes(CheckableButton, 0, { - selected, - }); - }); - }); - describe('selectMode', () => { it('is passed down to Transition', () => { const bulkActions = mountWithApp( @@ -232,16 +141,6 @@ describe('', () => { expect(cssTransitionComponent).toHaveReactProps({in: true}); }); }); - - it('is passed down to CheckableButton', () => { - const bulkActions = mountWithApp( - , - ); - const checkableButton = bulkActions.findAll(CheckableButton); - checkableButton.forEach((checkableButtonComponent) => { - expect(checkableButtonComponent).toHaveReactProps({selectMode: true}); - }); - }); }); describe('promotedActions', () => { @@ -277,10 +176,6 @@ describe('', () => { content: 'button 3', }, ], - paginatedSelectAllText: 'paginated select all text string', - selected: false, - accessibilityLabel: 'test-aria-label', - label: 'Test-Label', disabled: false, }; const bulkActions = mountWithApp(); @@ -321,10 +216,6 @@ describe('', () => { content: 'button 3', }, ], - paginatedSelectAllText: 'paginated select all text string', - selected: false, - accessibilityLabel: 'test-aria-label', - label: 'Test-Label', disabled: false, }; const bulkActions = mountWithApp(); @@ -354,10 +245,6 @@ describe('', () => { content: 'button 2', }, ], - paginatedSelectAllText: 'paginated select all text string', - selected: false, - accessibilityLabel: 'test-aria-label', - label: 'Test-Label', disabled: false, }; const bulkActions = mountWithApp(); @@ -372,36 +259,6 @@ describe('', () => { }); describe('disabled', () => { - const bulkActionProps: Props = { - bulkActions: ['button 3', 'button 4', 'button 5'], - promotedActions: [ - { - content: 'button 1', - }, - { - content: 'button 2', - }, - ], - paginatedSelectAllText: 'paginated select all text string', - selected: false, - accessibilityLabel: 'test-aria-label', - label: 'Test-Label', - disabled: true, - }; - - it('is passed down to CheckableButton', () => { - const {disabled} = bulkActionProps; - const bulkActions = mountWithApp(); - const checkableButtonLength = - bulkActions.findAll(CheckableButton).length; - - expect(bulkActions).toContainReactComponentTimes( - CheckableButton, - checkableButtonLength, - {disabled}, - ); - }); - it('will not overwrite the disabled value coming from a promotedAction', () => { const bulkActionProps: Props = { bulkActions: [], @@ -411,10 +268,6 @@ describe('', () => { content: 'button 1', }, ], - paginatedSelectAllText: 'paginated select all text string', - selected: false, - accessibilityLabel: 'test-aria-label', - label: 'Test-Label', disabled: false, }; const bulkActions = mountWithApp(); @@ -425,59 +278,8 @@ describe('', () => { }); }); - describe('paginatedSelectAllText', () => { - it('renders when provided', () => { - const {paginatedSelectAllText} = bulkActionProps; - const bulkActions = mountWithApp(); - expect( - bulkActions.find('div', {className: styles.PaginatedSelectAll}), - ).toContainReactText(paginatedSelectAllText); - }); - - it('does not render when not provided', () => { - const {paginatedSelectAllText, ...props} = bulkActionProps; - const bulkActions = mountWithApp(); - - expect(bulkActions).not.toContainReactComponent('div', { - className: styles.PaginatedSelectAll, - }); - }); - }); - - describe('paginatedSelectAllAction', () => { - it('onAction is called when CheckableButton is clicked', () => { - const spy = jest.fn(); - - const bulkActions = mountWithApp( - , - ); - bulkActions.find(Button, {onClick: spy})!.trigger('onClick'); - expect(spy).toHaveBeenCalled(); - }); - }); - describe('onMoreActionPopoverToggle', () => { - it('is invoked when the small screen popover is toggled', () => { - const spy = jest.fn(); - const bulkActions = mountWithApp( - , - ); - - bulkActions.find(BulkActionButton)?.trigger('onAction'); - - expect(spy).toHaveBeenCalledTimes(1); - }); - - it('is invoked when the large screen popover is toggled', () => { + it('is invoked when the popover is toggled', () => { const spy = jest.fn(); const bulkActions = mountWithApp( ', () => { }); }); - describe('smallScreen', () => { - it('renders only the large screen bulkactions if smallScreen is false', () => { + describe('className', () => { + it('renders with the Group className', () => { const bulkActions = mountWithApp( , ); - expect(bulkActions).not.toContainReactComponent('div', { - className: expect.stringContaining(styles['Group-smallScreen']), - }); - expect(bulkActions).toContainReactComponent('div', { - className: expect.stringContaining(styles['Group-largeScreen']), - }); - }); - - it('renders only the small screen bulkactions if smallScreen is true', () => { - const bulkActions = mountWithApp( - , - ); expect(bulkActions).toContainReactComponent('div', { - className: expect.stringContaining(styles['Group-smallScreen']), - }); - expect(bulkActions).not.toContainReactComponent('div', { - className: expect.stringContaining(styles['Group-largeScreen']), + className: expect.stringContaining(styles.Group), }); }); }); @@ -526,7 +313,7 @@ describe('', () => { // and ensure only the first element flex grows, we add this test to ensure the mark-up does not change it('has the mark-up structure to target the CheckableButton', () => { const bulkActions = mountWithApp( - , + , ); const checkableButton = bulkActions! diff --git a/polaris-react/src/components/CheckableButton/CheckableButton.scss b/polaris-react/src/components/CheckableButton/CheckableButton.scss index 20f51409b1f..7da58175973 100644 --- a/polaris-react/src/components/CheckableButton/CheckableButton.scss +++ b/polaris-react/src/components/CheckableButton/CheckableButton.scss @@ -74,6 +74,14 @@ $button-vertical-padding: calc( } } + &.CheckableButton-autoWidth { + width: auto; + + @media #{$p-breakpoints-sm-up} { + flex: none; + } + } + &.CheckableButton-selectMode { color: var(--p-text-subdued); font-weight: var(--p-font-weight-medium); diff --git a/polaris-react/src/components/CheckableButton/CheckableButton.tsx b/polaris-react/src/components/CheckableButton/CheckableButton.tsx index 646f27fa95b..ea25846dad0 100644 --- a/polaris-react/src/components/CheckableButton/CheckableButton.tsx +++ b/polaris-react/src/components/CheckableButton/CheckableButton.tsx @@ -15,11 +15,11 @@ export interface CheckableButtonProps { label?: string; selected?: boolean | 'indeterminate'; selectMode?: boolean; - smallScreen?: boolean; plain?: boolean; measuring?: boolean; disabled?: boolean; onToggleAll?(): void; + autoWidth?: boolean; } export function CheckableButton({ @@ -31,18 +31,16 @@ export function CheckableButton({ plain, measuring, disabled, - smallScreen, + autoWidth, }: CheckableButtonProps) { const checkBoxRef = useRef(null); const {registerCheckableButtons} = useContext(ResourceListContext); - let currentKey: CheckableButtonKey = 'bulkLg'; + let currentKey: CheckableButtonKey = 'plain'; - if (plain) { - currentKey = 'plain'; - } else if (smallScreen) { - currentKey = 'bulkSm'; + if (autoWidth) { + currentKey = 'selectAll'; } useEffect(() => { @@ -52,12 +50,17 @@ export function CheckableButton({ }, [currentKey, registerCheckableButtons]); const className = plain - ? classNames(styles.CheckableButton, styles['CheckableButton-plain']) + ? classNames( + styles.CheckableButton, + styles['CheckableButton-plain'], + autoWidth && styles['CheckableButton-autoWidth'], + ) : classNames( styles.CheckableButton, selectMode && styles['CheckableButton-selectMode'], selected && styles['CheckableButton-selected'], measuring && styles['CheckableButton-measuring'], + autoWidth && styles['CheckableButton-autoWidth'], ); return ( diff --git a/polaris-react/src/components/IndexTable/IndexTable.scss b/polaris-react/src/components/IndexTable/IndexTable.scss index aa645ded498..a19e2800eb1 100644 --- a/polaris-react/src/components/IndexTable/IndexTable.scss +++ b/polaris-react/src/components/IndexTable/IndexTable.scss @@ -9,10 +9,14 @@ --pc-index-table-bulk-actions: 36; --pc-index-table-loading-panel: 37; position: relative; - overflow: hidden; + // overflow: hidden; border-radius: inherit; } +.IndexTableWithBulkActions { + padding-bottom: var(--p-space-4); +} + .LoadingContainer-enter { opacity: 0; transform: translateY(-100%); @@ -484,14 +488,31 @@ $loading-panel-height: 53px; } .BulkActionsWrapper { + visibility: visible; + position: sticky; + z-index: var(--pc-index-table-bulk-actions); + left: 0; + width: 100%; + display: flex; + align-items: center; + justify-content: center; + bottom: var(--p-space-4); + margin-top: var(--p-space-4); +} + +.SelectAllActionsWrapper { visibility: visible; position: relative; z-index: var(--pc-index-table-bulk-actions); top: 0; left: 0; right: 0; - padding: var(--p-space-2); + padding: 0 var(--p-space-2) 0 calc(var(--p-space-2) + var(--p-space-05)); background: var(--p-surface); + + &.StickyTableHeader-condensed { + padding-top: calc(var(--p-space-2) + var(--p-space-05)); + } } $scroll-bar-size: var(--p-space-2); diff --git a/polaris-react/src/components/IndexTable/IndexTable.stories.tsx b/polaris-react/src/components/IndexTable/IndexTable.stories.tsx index 375aad5665b..f457b79cbe9 100644 --- a/polaris-react/src/components/IndexTable/IndexTable.stories.tsx +++ b/polaris-react/src/components/IndexTable/IndexTable.stories.tsx @@ -501,24 +501,34 @@ export function WithMultiplePromotedBulkActions() { } export function WithBulkActionsAndSelectionAcrossPages() { - const customers = [ - { - id: '3414', - url: 'customers/341', + const customers = Array.from({length: 50}, (_, num) => { + return { + id: `${num}`, + url: '/customers/341', name: 'Mae Jemison', location: 'Decatur, USA', orders: 20, - amountSpent: '$2,400', - }, - { - id: '2564', - url: 'customers/256', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - orders: 30, - amountSpent: '$140', - }, - ]; + amountSpent: '$24,00', + }; + }); + // const customers = [ + // { + // id: '3414', + // url: 'customers/341', + // name: 'Mae Jemison', + // location: 'Decatur, USA', + // orders: 20, + // amountSpent: '$2,400', + // }, + // { + // id: '2564', + // url: 'customers/256', + // name: 'Ellen Ochoa', + // location: 'Los Angeles, USA', + // orders: 30, + // amountSpent: '$140', + // }, + // ]; const resourceName = { singular: 'customer', plural: 'customers', diff --git a/polaris-react/src/components/IndexTable/IndexTable.tsx b/polaris-react/src/components/IndexTable/IndexTable.tsx index 771f861ec69..ef7cae240d8 100644 --- a/polaris-react/src/components/IndexTable/IndexTable.tsx +++ b/polaris-react/src/components/IndexTable/IndexTable.tsx @@ -15,6 +15,7 @@ import {Checkbox as PolarisCheckbox} from '../Checkbox'; import {EmptySearchResult} from '../EmptySearchResult'; // eslint-disable-next-line import/no-deprecated import {EventListener} from '../EventListener'; +import {SelectAllActions} from '../SelectAllActions'; import {Stack} from '../Stack'; import {Sticky} from '../Sticky'; import {Spinner} from '../Spinner'; @@ -544,6 +545,25 @@ function IndexTableBase({ const shouldShowBulkActions = (bulkActionsSelectable && selectedItemsCount) || isSmallScreenSelectable; + const bulkActionClassNames = classNames(styles.BulkActionsWrapper); + + const shouldShowActions = !condensed || selectedItemsCount; + const promotedActions = shouldShowActions ? promotedBulkActions : []; + const actions = shouldShowActions ? bulkActions : []; + + const bulkActionsMarkup = shouldShowBulkActions ? ( +
+ {loadingMarkup} + + +
+ ) : null; + const stickyHeaderMarkup = (
@@ -553,35 +573,25 @@ function IndexTableBase({ isSticky && styles['StickyTableHeader-isSticky'], ); - const bulkActionClassNames = classNames( - styles.BulkActionsWrapper, + const selectAllActionsClassName = classNames( + styles.SelectAllActionsWrapper, condensed && styles['StickyTableHeader-condensed'], isSticky && styles['StickyTableHeader-isSticky'], ); - const shouldShowActions = !condensed || selectedItemsCount; - const promotedActions = shouldShowActions ? promotedBulkActions : []; - const actions = shouldShowActions ? bulkActions : []; - - const bulkActionsMarkup = shouldShowBulkActions ? ( -
- {loadingMarkup} - +
) : null; @@ -629,9 +639,7 @@ function IndexTableBase({
); - const stickyContent = bulkActionsMarkup - ? bulkActionsMarkup - : headerMarkup; + const stickyContent = selectAllActionsMarkup ?? headerMarkup; return stickyContent; }} @@ -737,11 +745,20 @@ function IndexTableBase({
{emptyStateMarkup}
); + const bulkActionsWrapperClassNames = classNames( + Boolean(bulkActionsMarkup) && + selectMode && + styles.IndexTableWithBulkActions, + ); + return ( <>
- {!shouldShowBulkActions && !condensed && loadingMarkup} - {tableContentMarkup} +
+ {!shouldShowBulkActions && !condensed && loadingMarkup} + {tableContentMarkup} + {bulkActionsMarkup} +
{scrollBarMarkup} diff --git a/polaris-react/src/components/IndexTable/tests/IndexTable.test.tsx b/polaris-react/src/components/IndexTable/tests/IndexTable.test.tsx index a069ce613bc..f928f15e7a6 100644 --- a/polaris-react/src/components/IndexTable/tests/IndexTable.test.tsx +++ b/polaris-react/src/components/IndexTable/tests/IndexTable.test.tsx @@ -13,6 +13,7 @@ import {Checkbox} from '../../Checkbox'; import {Badge} from '../../Badge'; import {Text} from '../../Text'; import {BulkActions} from '../../BulkActions'; +import {SelectAllActions} from '../../SelectAllActions'; import {IndexTable, IndexTableProps} from '../IndexTable'; import type {IndexTableSortDirection} from '../IndexTable'; import {ScrollContainer} from '../components'; @@ -385,7 +386,7 @@ describe('', () => { }); }); - describe('BulkActions', () => { + describe('SelectAllActions', () => { const originalInnerWidth = window.innerWidth; afterEach(() => { @@ -411,7 +412,7 @@ describe('', () => { ); index - .find(BulkActions)! + .find(SelectAllActions)! .triggerKeypath('paginatedSelectAllAction.onAction'); expect(onSelectionChangeSpy).toHaveBeenCalledWith( @@ -437,7 +438,7 @@ describe('', () => { {mockTableItems.map(mockRenderRow)} , ); - expect(index.find(BulkActions)).toContainReactText(customString); + expect(index.find(SelectAllActions)).toContainReactText(customString); }); it('toggles all page resources when onToggleAll is triggered', () => { @@ -456,7 +457,7 @@ describe('', () => { , ); - index.find(BulkActions)!.trigger('onToggleAll'); + index.find(SelectAllActions)!.trigger('onToggleAll'); expect(onSelectionChangeSpy).toHaveBeenCalledWith( SelectionType.Page, diff --git a/polaris-react/src/components/ResourceList/ResourceList.scss b/polaris-react/src/components/ResourceList/ResourceList.scss index e0d7039f080..477a881969a 100644 --- a/polaris-react/src/components/ResourceList/ResourceList.scss +++ b/polaris-react/src/components/ResourceList/ResourceList.scss @@ -155,6 +155,24 @@ $breakpoints-empty-search-results-height-up: '(min-height: #{breakpoint(600px)}) } .BulkActionsWrapper { + z-index: resource-list(bulk-actions-wrapper-stacking-order); + visibility: visible; + position: sticky; + left: 0; + width: 100%; + display: flex; + align-items: center; + justify-content: center; + bottom: var(--p-space-4); + margin-top: var(--p-space-4); + + @media #{$p-breakpoints-sm-up} { + flex: 0 1 auto; + align-self: flex-start; + } +} + +.SelectAllActionsWrapper { position: relative; z-index: resource-list(bulk-actions-wrapper-stacking-order); width: 100%; @@ -198,6 +216,10 @@ $breakpoints-empty-search-results-height-up: '(min-height: #{breakpoint(600px)}) position: relative; } +.ResourceListWrapperWithBulkActions { + padding-bottom: var(--p-space-4); +} + .ResourceList { position: relative; z-index: resource-list(list-stacking-order); diff --git a/polaris-react/src/components/ResourceList/ResourceList.stories.tsx b/polaris-react/src/components/ResourceList/ResourceList.stories.tsx index 6b614ff7844..7589242a30c 100644 --- a/polaris-react/src/components/ResourceList/ResourceList.stories.tsx +++ b/polaris-react/src/components/ResourceList/ResourceList.stories.tsx @@ -248,6 +248,81 @@ export function WithBulkActions() { } } +export function WithBulkActionsAndManyItems() { + const [selectedItems, setSelectedItems] = useState([]); + + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const items = Array.from({length: 50}, (_, num) => { + return { + id: `${num}`, + url: '/customers/341', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$24,00', + }; + }); + + const promotedBulkActions = [ + { + content: 'Edit customers', + onAction: () => console.log('Todo: implement bulk edit'), + }, + ]; + + const bulkActions = [ + { + content: 'Add tags', + onAction: () => console.log('Todo: implement bulk add tags'), + }, + { + content: 'Remove tags', + onAction: () => console.log('Todo: implement bulk remove tags'), + }, + { + content: 'Delete customers', + onAction: () => console.log('Todo: implement bulk delete'), + }, + ]; + + return ( + + + + ); + + function renderItem(item) { + const {id, url, name, location} = item; + const media = ; + + return ( + +

+ {name} +

+
{location}
+
+ ); + } +} + export function WithLoadingState() { const [selectedItems, setSelectedItems] = useState([]); diff --git a/polaris-react/src/components/ResourceList/ResourceList.tsx b/polaris-react/src/components/ResourceList/ResourceList.tsx index 2011e6f806b..74761a4a241 100644 --- a/polaris-react/src/components/ResourceList/ResourceList.tsx +++ b/polaris-react/src/components/ResourceList/ResourceList.tsx @@ -32,6 +32,7 @@ import {useI18n} from '../../utilities/i18n'; import {ResourceItem} from '../ResourceItem'; import {useLazyRef} from '../../utilities/use-lazy-ref'; import {BulkActions, BulkActionsProps} from '../BulkActions'; +import {SelectAllActions} from '../SelectAllActions'; import {CheckableButton} from '../CheckableButton'; import styles from './ResourceList.scss'; @@ -200,7 +201,7 @@ export const ResourceList: ResourceListType = function ResourceList({ selectable, ); - const bulkSelectState = (): boolean | 'indeterminate' => { + const selectAllSelectState = (): boolean | 'indeterminate' => { let selectState: boolean | 'indeterminate' = 'indeterminate'; if ( !selectedItems || @@ -244,7 +245,7 @@ export const ResourceList: ResourceListType = function ResourceList({ } }; - const bulkActionsLabel = () => { + const selectAllActionsLabel = () => { const selectedItemsCount = selectedItems === SELECT_ALL_ITEMS ? `${items.length}+` @@ -255,7 +256,7 @@ export const ResourceList: ResourceListType = function ResourceList({ }); }; - const bulkActionsAccessibilityLabel = () => { + const selectAllActionsAccessibilityLabel = () => { const selectedItemsCount = selectedItems.length; const totalItemsCount = items.length; const allSelected = selectedItemsCount === totalItemsCount; @@ -516,11 +517,11 @@ export const ResourceList: ResourceListType = function ResourceList({ let checkbox: CheckboxHandles | undefined; if (isBreakpointsXS()) { - checkbox = checkableButtons.get('bulkSm'); + checkbox = checkableButtons.get('selectAll'); } else if (newlySelectedItems.length === 0) { checkbox = checkableButtons.get('plain'); } else { - checkbox = checkableButtons.get('bulkLg'); + checkbox = checkableButtons.get('selectAll'); } if (onSelectionChange) { @@ -533,21 +534,30 @@ export const ResourceList: ResourceListType = function ResourceList({ }, 0); }; + const selectAllActionsMarkup = isSelectable ? ( +
+ +
+ ) : null; + const bulkActionsMarkup = isSelectable ? (
) : null; @@ -595,7 +605,7 @@ export const ResourceList: ResourceListType = function ResourceList({ const checkableButtonMarkup = isSelectable ? (
({ {sortingSelectMarkup} {selectButtonMarkup}
- {bulkActionsMarkup} + {selectAllActionsMarkup}
); }} @@ -725,13 +735,21 @@ export const ResourceList: ResourceListType = function ResourceList({ return ( -
+
{filterControlMarkup} {headerMarkup} {listMarkup} {emptySearchStateMarkup} {emptyStateMarkup} {loadingWithoutItemsMarkup} + {bulkActionsMarkup}
); diff --git a/polaris-react/src/components/ResourceList/tests/ResourceList.test.tsx b/polaris-react/src/components/ResourceList/tests/ResourceList.test.tsx index 15bf63a6e0f..a0bd3c114c4 100644 --- a/polaris-react/src/components/ResourceList/tests/ResourceList.test.tsx +++ b/polaris-react/src/components/ResourceList/tests/ResourceList.test.tsx @@ -2,6 +2,7 @@ import React from 'react'; import {mountWithApp} from 'tests/utilities'; import {BulkActions} from '../../BulkActions'; +import {SelectAllActions} from '../../SelectAllActions'; import {Button} from '../../Button'; import {CheckableButton} from '../../CheckableButton'; import {EmptySearchResult} from '../../EmptySearchResult'; @@ -85,6 +86,13 @@ describe('', () => { expect(resourceList).not.toContainReactComponent(CheckableButton); }); + it('does not render a `SelectAllActions` if the `selectable` prop is not provided', () => { + const resourceList = mountWithApp( + , + ); + expect(resourceList).not.toContainReactComponent(SelectAllActions); + }); + it('does render bulk actions if the promotedBulkActions prop is provided', () => { const resourceList = mountWithApp( ', () => { ); expect(resourceList).toContainReactComponent(CheckableButton); }); + + it('renders a `SelectAllActions` if the `selectable` prop is true', () => { + const resourceList = mountWithApp( + , + ); + expect(resourceList).toContainReactComponent(SelectAllActions); + }); }); describe('hasMoreItems', () => { - it('does not add a prop of paginatedSelectAllAction to BulkActions if omitted', () => { + it('does not add a prop of paginatedSelectAllAction to SelectAllActions if omitted', () => { const resourceList = mountWithApp( ', () => { bulkActions={bulkActions} />, ); - expect(resourceList).toContainReactComponent(BulkActions, { + expect(resourceList).toContainReactComponent(SelectAllActions, { paginatedSelectAllAction: undefined, }); }); - it('adds a prop of paginatedSelectAllAction to BulkActions if included', () => { + it('adds a prop of paginatedSelectAllAction to SelectAllActions if included', () => { const resourceList = mountWithApp( ', () => { />, ); expect( - resourceList.find(BulkActions)!.props.paginatedSelectAllAction, + resourceList.find(SelectAllActions)!.props.paginatedSelectAllAction, ).toBeDefined(); }); }); @@ -272,8 +287,8 @@ describe('', () => { }); }); - describe('bulkActionsAccessibilityLabel', () => { - it('provides the BulkActions with the right accessibilityLabel if there’s 1 item and it isn’t selected', () => { + describe('selectAllActionsAccessibilityLabel', () => { + it('provides the SelectAllActions with the right accessibilityLabel if there’s 1 item and it isn’t selected', () => { const resourceList = mountWithApp( ', () => { bulkActions={bulkActions} />, ); - expect(resourceList).toContainReactComponent(BulkActions, { + expect(resourceList).toContainReactComponent(SelectAllActions, { accessibilityLabel: 'Select item', }); }); - it('provides the BulkActions with the right accessibilityLabel if there’s 1 item and it is selected', () => { + it('provides the SelectAllActions with the right accessibilityLabel if there’s 1 item and it is selected', () => { const resourceList = mountWithApp( ', () => { selectedItems={['1']} />, ); - expect(resourceList).toContainReactComponent(BulkActions, { + expect(resourceList).toContainReactComponent(SelectAllActions, { accessibilityLabel: 'Deselect item', }); }); - it('provides the BulkActions with the right accessibilityLabel if there are multiple items and they are selected', () => { + it('provides the SelectAllActions with the right accessibilityLabel if there are multiple items and they are selected', () => { const resourceList = mountWithApp( ', () => { selectedItems={['5', '6', '7']} />, ); - expect(resourceList).toContainReactComponent(BulkActions, { + expect(resourceList).toContainReactComponent(SelectAllActions, { accessibilityLabel: 'Deselect all 3 items', }); }); - it('provides the BulkActions with the right accessibilityLabel if there’s multiple items and some or none are selected', () => { + it('provides the SelectAllActions with the right accessibilityLabel if there’s multiple items and some or none are selected', () => { const resourceList = mountWithApp( ', () => { bulkActions={bulkActions} />, ); - expect(resourceList).toContainReactComponent(BulkActions, { + expect(resourceList).toContainReactComponent(SelectAllActions, { accessibilityLabel: 'Select all 3 items', }); }); @@ -951,8 +966,8 @@ describe('', () => { .trigger('onToggleAll'); const deselectAllCheckbox = resourceList - .findAll(CheckableButton) - .find((ele) => !ele.prop('plain'))! + .find(SelectAllActions)! + .find(CheckableButton)! .find('input', {type: 'checkbox'})!; expect(document.activeElement).toBe(deselectAllCheckbox.domNode); @@ -969,12 +984,12 @@ describe('', () => { ); resourceList - .findAll(CheckableButton) - .find((ele) => !ele.prop('plain'))! + .find(SelectAllActions)! + .find(CheckableButton)! .trigger('onToggleAll'); const selectAllCheckableCheckbox = resourceList - .find(CheckableButton, {plain: true})! + .findAll(CheckableButton, {plain: true})[0]! .find('input', {type: 'checkbox'})!; expect(document.activeElement).toBe( @@ -1222,6 +1237,7 @@ describe('', () => { const resourceList = mountWithApp( ', () => { />, ); - expect(resourceList).toContainReactComponent(BulkActions, { + expect(resourceList).toContainReactComponent(SelectAllActions, { paginatedSelectAllAction: { content: 'Select all 2+ customers in this filter', onAction: expect.any(Function), @@ -1254,7 +1270,7 @@ describe('', () => { resourceList.find(BulkActions)!.find(Button)!.trigger('onClick'); - expect(resourceList).toContainReactComponent(BulkActions, { + expect(resourceList).toContainReactComponent(SelectAllActions, { paginatedSelectAllText: 'All 2+ customers in this filter are selected.', }); }); @@ -1263,6 +1279,7 @@ describe('', () => { const resourceList = mountWithApp( ', () => { />, ); - expect(resourceList).toContainReactComponent(BulkActions, { + expect(resourceList).toContainReactComponent(SelectAllActions, { paginatedSelectAllAction: { content: 'Select all 2+ customers in your store', onAction: expect.any(Function), @@ -1293,7 +1310,7 @@ describe('', () => { resourceList.find(BulkActions)!.find(Button)!.trigger('onClick'); - expect(resourceList).toContainReactComponent(BulkActions, { + expect(resourceList).toContainReactComponent(SelectAllActions, { paginatedSelectAllText: 'All 2+ customers in your store are selected.', }); }); diff --git a/polaris-react/src/components/SelectAllActions/SelectAllActions.scss b/polaris-react/src/components/SelectAllActions/SelectAllActions.scss new file mode 100644 index 00000000000..58d0f921916 --- /dev/null +++ b/polaris-react/src/components/SelectAllActions/SelectAllActions.scss @@ -0,0 +1,22 @@ +.SelectAllActions { + display: flex; + gap: var(--p-space-025); + align-items: center; + justify-content: flex-start; +} + +.SelectAllActions-entering, +.SelectAllActions-exiting { + opacity: 0; + display: flex; +} + +.SelectAllActions-entered { + opacity: 1; + display: flex; +} + +.SelectAllActions-exited { + opacity: 0; + display: none; +} diff --git a/polaris-react/src/components/SelectAllActions/SelectAllActions.tsx b/polaris-react/src/components/SelectAllActions/SelectAllActions.tsx new file mode 100644 index 00000000000..8399b968c1c --- /dev/null +++ b/polaris-react/src/components/SelectAllActions/SelectAllActions.tsx @@ -0,0 +1,96 @@ +import React from 'react'; +import {Transition} from 'react-transition-group'; + +import {classNames} from '../../utilities/css'; +import type {Action} from '../../types'; +import {Button} from '../Button'; +import {CheckableButton} from '../CheckableButton'; + +import styles from './SelectAllActions.scss'; + +type TransitionStatus = 'entering' | 'entered' | 'exiting' | 'exited'; + +export interface SelectAllActionsProps { + /** Visually hidden text for screen readers */ + accessibilityLabel?: string; + /** Whether to render the small screen BulkActions or not */ + smallScreen?: boolean; + /** Label for the bulk actions */ + label?: string; + /** State of the bulk actions checkbox */ + selected?: boolean | 'indeterminate'; + /** List is in a selectable state */ + selectMode?: boolean; + /** Text to select all across pages */ + paginatedSelectAllText?: string; + /** Action for selecting all across pages */ + paginatedSelectAllAction?: Action; + /** Disables bulk actions */ + disabled?: boolean; + /** Callback when the select all checkbox is clicked */ + onToggleAll?(): void; +} + +export function SelectAllActions({ + accessibilityLabel, + smallScreen, + label, + selected, + selectMode, + paginatedSelectAllText, + paginatedSelectAllAction, + disabled, + onToggleAll, +}: SelectAllActionsProps) { + const paginatedSelectAllActionMarkup = paginatedSelectAllAction ? ( + + ) : null; + + const paginatedSelectAllTextMarkup = + paginatedSelectAllText && paginatedSelectAllAction ? ( + {paginatedSelectAllText} + ) : ( + paginatedSelectAllText + ); + + const paginatedSelectAllMarkup = + paginatedSelectAllActionMarkup || paginatedSelectAllTextMarkup ? ( +
+ {paginatedSelectAllTextMarkup} {paginatedSelectAllActionMarkup} +
+ ) : null; + + const checkableButtonProps = { + accessibilityLabel, + label, + selected, + selectMode, + onToggleAll, + disabled, + plain: !smallScreen, + autoWidth: true, + }; + const markup = ( + + {(status: TransitionStatus) => { + const wrapperClasses = classNames( + styles.SelectAllActions, + styles[`SelectAllActions-${status}`], + ); + return ( +
+ + {paginatedSelectAllMarkup} +
+ ); + }} +
+ ); + return markup; +} diff --git a/polaris-react/src/components/SelectAllActions/index.ts b/polaris-react/src/components/SelectAllActions/index.ts new file mode 100644 index 00000000000..ab80555384b --- /dev/null +++ b/polaris-react/src/components/SelectAllActions/index.ts @@ -0,0 +1 @@ +export * from './SelectAllActions'; diff --git a/polaris-react/src/components/SelectAllActions/tests/SelectAllActions.test.tsx b/polaris-react/src/components/SelectAllActions/tests/SelectAllActions.test.tsx new file mode 100644 index 00000000000..553cb08f0a9 --- /dev/null +++ b/polaris-react/src/components/SelectAllActions/tests/SelectAllActions.test.tsx @@ -0,0 +1,230 @@ +import React from 'react'; +import {Transition, CSSTransition} from 'react-transition-group'; +import {mountWithApp} from 'tests/utilities'; + +import {CheckableButton} from '../../CheckableButton'; +import {Button} from '../../Button'; +import {SelectAllActions} from '../SelectAllActions'; +import styles from '../SelectAllActions.scss'; + +interface Props { + paginatedSelectAllText: string; + selected: boolean; + accessibilityLabel: string; + label: string; + disabled: boolean; +} + +const selectAllActionProps: Props = { + paginatedSelectAllText: 'paginated select all text string', + selected: false, + accessibilityLabel: 'test-aria-label', + label: 'Test-Label', + disabled: false, +}; + +describe('', () => { + describe('loading', () => { + it('disables buttons', () => { + const selectAllActions = mountWithApp( + {}}} + disabled + />, + ); + + expect(selectAllActions).toContainReactComponentTimes('button', 1, { + 'aria-disabled': true, + }); + }); + }); + + describe('props', () => { + describe('accessibilityLabel', () => { + it('is passed down to CheckableButton', () => { + const {accessibilityLabel} = selectAllActionProps; + const selectAllActions = mountWithApp( + , + ); + const checkableButtonLength = + selectAllActions.findAll(CheckableButton).length; + + expect(selectAllActions).toContainReactComponentTimes( + CheckableButton, + checkableButtonLength, + { + accessibilityLabel, + }, + ); + }); + + it('does not pass down to CheckableButton when the property is not provided', () => { + const {accessibilityLabel, ...props} = selectAllActionProps; + const selectAllActions = mountWithApp(); + + expect(selectAllActions).toContainReactComponentTimes( + CheckableButton, + 0, + { + accessibilityLabel, + }, + ); + }); + }); + + describe('label', () => { + it('is passed down to CheckableButton', () => { + const {label} = selectAllActionProps; + const selectAllActions = mountWithApp( + , + ); + const checkableButtonLength = + selectAllActions.findAll(CheckableButton).length; + expect(selectAllActions).toContainReactComponentTimes( + CheckableButton, + checkableButtonLength, + {label}, + ); + }); + + it('does not pass down to CheckableButton when the property is not provided', () => { + const {label, ...props} = selectAllActionProps; + const selectAllActions = mountWithApp(); + expect(selectAllActions).toContainReactComponentTimes( + CheckableButton, + 0, + { + label, + }, + ); + }); + }); + + describe('selected', () => { + it('is passed down to CheckableButton', () => { + const {selected} = selectAllActionProps; + const selectAllActions = mountWithApp( + , + ); + const checkableButtonLength = + selectAllActions.findAll(CheckableButton).length; + + expect(selectAllActions).toContainReactComponentTimes( + CheckableButton, + checkableButtonLength, + {selected}, + ); + }); + + it('does not pass down to CheckableButton when the property is not provided', () => { + const {selected, ...props} = selectAllActionProps; + const selectAllActions = mountWithApp(); + + expect(selectAllActions).toContainReactComponentTimes( + CheckableButton, + 0, + { + selected, + }, + ); + }); + }); + + describe('selectMode', () => { + it('is passed down to Transition', () => { + const selectAllActions = mountWithApp( + , + ); + + expect(selectAllActions).toContainReactComponent(Transition, { + in: true, + }); + }); + + it('is passed down to CSSTransition', () => { + const selectAllActions = mountWithApp( + , + ); + + const cssTransition = selectAllActions.findAll(CSSTransition, { + appear: true, + }); + cssTransition.forEach((cssTransitionComponent) => { + expect(cssTransitionComponent).toHaveReactProps({in: true}); + }); + }); + + it('is passed down to CheckableButton', () => { + const selectAllActions = mountWithApp( + , + ); + const checkableButton = selectAllActions.findAll(CheckableButton); + checkableButton.forEach((checkableButtonComponent) => { + expect(checkableButtonComponent).toHaveReactProps({selectMode: true}); + }); + }); + }); + + describe('disabled', () => { + const selectAllActionProps: Props = { + paginatedSelectAllText: 'paginated select all text string', + selected: false, + accessibilityLabel: 'test-aria-label', + label: 'Test-Label', + disabled: true, + }; + + it('is passed down to CheckableButton', () => { + const {disabled} = selectAllActionProps; + const selectAllActions = mountWithApp( + , + ); + const checkableButtonLength = + selectAllActions.findAll(CheckableButton).length; + + expect(selectAllActions).toContainReactComponentTimes( + CheckableButton, + checkableButtonLength, + {disabled}, + ); + }); + }); + + describe('paginatedSelectAllText', () => { + it('renders when provided', () => { + const {paginatedSelectAllText} = selectAllActionProps; + const selectAllActions = mountWithApp( + , + ); + expect( + selectAllActions.find('div', {className: styles.PaginatedSelectAll}), + ).toContainReactText(paginatedSelectAllText); + }); + + it('does not render when not provided', () => { + const {paginatedSelectAllText, ...props} = selectAllActionProps; + const selectAllActions = mountWithApp(); + + expect(selectAllActions).not.toContainReactComponent('div', { + className: styles.PaginatedSelectAll, + }); + }); + }); + + describe('paginatedSelectAllAction', () => { + it('onAction is called when CheckableButton is clicked', () => { + const spy = jest.fn(); + + const selectAllActions = mountWithApp( + , + ); + selectAllActions.find(Button, {onClick: spy})!.trigger('onClick'); + expect(spy).toHaveBeenCalled(); + }); + }); + }); +}); diff --git a/polaris-react/src/components/index.ts b/polaris-react/src/components/index.ts new file mode 100644 index 00000000000..f28de61ee83 --- /dev/null +++ b/polaris-react/src/components/index.ts @@ -0,0 +1 @@ +export {SelectAllActions} from './SelectAllActions'; diff --git a/polaris-react/src/utilities/resource-list/types.ts b/polaris-react/src/utilities/resource-list/types.ts index 1a15e320fd7..21c64f61205 100644 --- a/polaris-react/src/utilities/resource-list/types.ts +++ b/polaris-react/src/utilities/resource-list/types.ts @@ -1,7 +1,7 @@ import type {CheckboxHandles} from '../../types'; export type ResourceListSelectedItems = string[] | 'All'; -export type CheckableButtonKey = 'plain' | 'bulkSm' | 'bulkLg'; +export type CheckableButtonKey = 'plain' | 'selectAll'; export type CheckableButtons = Map; export const SELECT_ALL_ITEMS = 'All'; From c0842f0f611eece10bff424758d4e19a5f848e3c Mon Sep 17 00:00:00 2001 From: Marc Thomas Date: Wed, 28 Sep 2022 14:26:47 +0100 Subject: [PATCH 02/32] chore: add changeset --- .changeset/odd-spoons-dance.md | 5 +++ .../CheckableButton/CheckableButton.scss | 1 + .../CheckableButton/CheckableButton.tsx | 6 +++- .../SelectAllActions/SelectAllActions.scss | 35 +++++++++++++++++++ .../SelectAllActions/SelectAllActions.tsx | 32 ++++++++--------- .../tests/SelectAllActions.test.tsx | 15 ++++---- 6 files changed, 71 insertions(+), 23 deletions(-) create mode 100644 .changeset/odd-spoons-dance.md diff --git a/.changeset/odd-spoons-dance.md b/.changeset/odd-spoons-dance.md new file mode 100644 index 00000000000..bc35969d440 --- /dev/null +++ b/.changeset/odd-spoons-dance.md @@ -0,0 +1,5 @@ +--- +'@shopify/polaris': minor +--- + +Separate BulkActions and SelectAllActions for new bulk selection experience" diff --git a/polaris-react/src/components/CheckableButton/CheckableButton.scss b/polaris-react/src/components/CheckableButton/CheckableButton.scss index 7da58175973..f48ec71bb43 100644 --- a/polaris-react/src/components/CheckableButton/CheckableButton.scss +++ b/polaris-react/src/components/CheckableButton/CheckableButton.scss @@ -76,6 +76,7 @@ $button-vertical-padding: calc( &.CheckableButton-autoWidth { width: auto; + font-size: var(--p-font-size-75); @media #{$p-breakpoints-sm-up} { flex: none; diff --git a/polaris-react/src/components/CheckableButton/CheckableButton.tsx b/polaris-react/src/components/CheckableButton/CheckableButton.tsx index ea25846dad0..310ab1020be 100644 --- a/polaris-react/src/components/CheckableButton/CheckableButton.tsx +++ b/polaris-react/src/components/CheckableButton/CheckableButton.tsx @@ -20,6 +20,7 @@ export interface CheckableButtonProps { disabled?: boolean; onToggleAll?(): void; autoWidth?: boolean; + ariaLive?: 'off' | 'assertive' | 'polite'; } export function CheckableButton({ @@ -32,6 +33,7 @@ export function CheckableButton({ measuring, disabled, autoWidth, + ariaLive, }: CheckableButtonProps) { const checkBoxRef = useRef(null); @@ -75,7 +77,9 @@ export function CheckableButton({ ref={checkBoxRef} />
- {label} + + {label} + ); } diff --git a/polaris-react/src/components/SelectAllActions/SelectAllActions.scss b/polaris-react/src/components/SelectAllActions/SelectAllActions.scss index 58d0f921916..c610628b31c 100644 --- a/polaris-react/src/components/SelectAllActions/SelectAllActions.scss +++ b/polaris-react/src/components/SelectAllActions/SelectAllActions.scss @@ -1,3 +1,5 @@ +@import '../../styles/common'; + .SelectAllActions { display: flex; gap: var(--p-space-025); @@ -20,3 +22,36 @@ opacity: 0; display: none; } + +.PaginatedSelectAll { + font-size: var(--p-font-size-75); + font-weight: var(--p-font-weight-semibold); +} + +.AllAction { + font-size: var(--p-font-size-75); + font-weight: var(--p-font-weight-semibold); + border: 0; + background: none; + padding: 0; + cursor: pointer; + color: var(--p-interactive); + @include focus-ring; + + &:hover, + &:focus { + color: var(--p-interactive-hovered); + } + + &:active { + color: var(--p-interactive-pressed); + } + + &:focus { + @include no-focus-ring; + } + + &:focus:not(:active) { + @include focus-ring($style: 'focused'); + } +} diff --git a/polaris-react/src/components/SelectAllActions/SelectAllActions.tsx b/polaris-react/src/components/SelectAllActions/SelectAllActions.tsx index 8399b968c1c..a30a3b96b45 100644 --- a/polaris-react/src/components/SelectAllActions/SelectAllActions.tsx +++ b/polaris-react/src/components/SelectAllActions/SelectAllActions.tsx @@ -3,12 +3,13 @@ import {Transition} from 'react-transition-group'; import {classNames} from '../../utilities/css'; import type {Action} from '../../types'; -import {Button} from '../Button'; +import {UnstyledButton} from '../UnstyledButton'; import {CheckableButton} from '../CheckableButton'; import styles from './SelectAllActions.scss'; type TransitionStatus = 'entering' | 'entered' | 'exiting' | 'exited'; +type AriaLive = 'off' | 'assertive' | 'polite' | undefined; export interface SelectAllActionsProps { /** Visually hidden text for screen readers */ @@ -43,38 +44,37 @@ export function SelectAllActions({ onToggleAll, }: SelectAllActionsProps) { const paginatedSelectAllActionMarkup = paginatedSelectAllAction ? ( - + ) : null; - const paginatedSelectAllTextMarkup = - paginatedSelectAllText && paginatedSelectAllAction ? ( - {paginatedSelectAllText} - ) : ( - paginatedSelectAllText - ); + const hasTextAndAction = paginatedSelectAllText && paginatedSelectAllAction; - const paginatedSelectAllMarkup = - paginatedSelectAllActionMarkup || paginatedSelectAllTextMarkup ? ( -
- {paginatedSelectAllTextMarkup} {paginatedSelectAllActionMarkup} -
- ) : null; + const paginatedSelectAllMarkup = paginatedSelectAllActionMarkup ? ( +
+ {paginatedSelectAllActionMarkup} +
+ ) : null; + + const ariaLive: AriaLive = hasTextAndAction ? 'polite' : undefined; const checkableButtonProps = { accessibilityLabel, - label, + label: hasTextAndAction ? paginatedSelectAllText : label, selected, selectMode, onToggleAll, disabled, plain: !smallScreen, autoWidth: true, + ariaLive, }; const markup = ( diff --git a/polaris-react/src/components/SelectAllActions/tests/SelectAllActions.test.tsx b/polaris-react/src/components/SelectAllActions/tests/SelectAllActions.test.tsx index 553cb08f0a9..d59b19f14d5 100644 --- a/polaris-react/src/components/SelectAllActions/tests/SelectAllActions.test.tsx +++ b/polaris-react/src/components/SelectAllActions/tests/SelectAllActions.test.tsx @@ -3,7 +3,7 @@ import {Transition, CSSTransition} from 'react-transition-group'; import {mountWithApp} from 'tests/utilities'; import {CheckableButton} from '../../CheckableButton'; -import {Button} from '../../Button'; +import {UnstyledButton} from '../../UnstyledButton'; import {SelectAllActions} from '../SelectAllActions'; import styles from '../SelectAllActions.scss'; @@ -195,11 +195,12 @@ describe('', () => { it('renders when provided', () => { const {paginatedSelectAllText} = selectAllActionProps; const selectAllActions = mountWithApp( - , + {}}} + />, ); - expect( - selectAllActions.find('div', {className: styles.PaginatedSelectAll}), - ).toContainReactText(paginatedSelectAllText); + expect(selectAllActions).toContainReactText(paginatedSelectAllText); }); it('does not render when not provided', () => { @@ -222,7 +223,9 @@ describe('', () => { paginatedSelectAllAction={{content: 'content', onAction: spy}} />, ); - selectAllActions.find(Button, {onClick: spy})!.trigger('onClick'); + selectAllActions + .find(UnstyledButton, {onClick: spy})! + .trigger('onClick'); expect(spy).toHaveBeenCalled(); }); }); From ec8d0cee95aa8d039f2c0ada00df567a38fbb14d Mon Sep 17 00:00:00 2001 From: Marc Thomas Date: Wed, 28 Sep 2022 15:05:27 +0100 Subject: [PATCH 03/32] chore: fix erroneous style rules --- polaris-react/src/components/IndexTable/IndexTable.scss | 2 +- polaris-react/src/components/ResourceList/ResourceList.scss | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/polaris-react/src/components/IndexTable/IndexTable.scss b/polaris-react/src/components/IndexTable/IndexTable.scss index a19e2800eb1..55f123466dc 100644 --- a/polaris-react/src/components/IndexTable/IndexTable.scss +++ b/polaris-react/src/components/IndexTable/IndexTable.scss @@ -492,11 +492,11 @@ $loading-panel-height: 53px; position: sticky; z-index: var(--pc-index-table-bulk-actions); left: 0; + bottom: var(--p-space-4); width: 100%; display: flex; align-items: center; justify-content: center; - bottom: var(--p-space-4); margin-top: var(--p-space-4); } diff --git a/polaris-react/src/components/ResourceList/ResourceList.scss b/polaris-react/src/components/ResourceList/ResourceList.scss index 477a881969a..06363732b94 100644 --- a/polaris-react/src/components/ResourceList/ResourceList.scss +++ b/polaris-react/src/components/ResourceList/ResourceList.scss @@ -158,12 +158,12 @@ $breakpoints-empty-search-results-height-up: '(min-height: #{breakpoint(600px)}) z-index: resource-list(bulk-actions-wrapper-stacking-order); visibility: visible; position: sticky; + bottom: var(--p-space-4); left: 0; width: 100%; display: flex; align-items: center; justify-content: center; - bottom: var(--p-space-4); margin-top: var(--p-space-4); @media #{$p-breakpoints-sm-up} { From 3bf5d317558d2eb186c20d260acbd29bf85fce03 Mon Sep 17 00:00:00 2001 From: Marc Thomas Date: Tue, 4 Oct 2022 13:51:57 +0100 Subject: [PATCH 04/32] chore: add focus ability --- .../components/BulkActions/BulkActions.tsx | 44 ++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/polaris-react/src/components/BulkActions/BulkActions.tsx b/polaris-react/src/components/BulkActions/BulkActions.tsx index 049c447c6d2..eb54ab43c92 100644 --- a/polaris-react/src/components/BulkActions/BulkActions.tsx +++ b/polaris-react/src/components/BulkActions/BulkActions.tsx @@ -5,6 +5,7 @@ import {debounce} from '../../utilities/debounce'; import {classNames} from '../../utilities/css'; import {useI18n} from '../../utilities/i18n'; import {clamp} from '../../utilities/clamp'; +import {findFirstKeyboardFocusableNode} from '../../utilities/focus'; import type { BadgeAction, DisableableAction, @@ -63,6 +64,7 @@ class BulkActionsInner extends PureComponent { private containerNode: HTMLElement | null = null; private buttonsNode: HTMLElement | null = null; private moreActionsNode: HTMLElement | null = null; + private activatorNode: Element | null = null; private groupNode = createRef(); private promotedActionsWidths: number[] = []; private bulkActionsWidth = 0; @@ -89,6 +91,25 @@ class BulkActionsInner extends PureComponent { {trailing: true}, ); + private focusContent() { + if (this.containerNode == null) { + return; + } + + requestAnimationFrame(() => { + if (this.containerNode == null) { + return; + } + + const focusableChild = findFirstKeyboardFocusableNode(this.containerNode); + if (focusableChild) { + focusableChild.focus({ + preventScroll: process.env.NODE_ENV === 'development', + }); + } + }); + } + private numberOfPromotedActionsToRender(): number { const {promotedActions} = this.props; const {containerWidth, measuring} = this.state; @@ -178,6 +199,11 @@ class BulkActionsInner extends PureComponent { this.addedMoreActionsWidthForMeasuring : 0; + if (document?.activeElement) { + this.activatorNode = document.activeElement; + } + this.focusContent(); + if (this.containerNode) { this.setState({ containerWidth: this.containerNode.getBoundingClientRect().width, @@ -321,7 +347,11 @@ class BulkActionsInner extends PureComponent { ); - return
{group}
; + return ( +
+ {group} +
+ ); } private isNewBadgeInBadgeActions() { @@ -365,6 +395,18 @@ class BulkActionsInner extends PureComponent { this.promotedActionsWidths.push(width); } }; + + private handleBlur = (event: React.FocusEvent) => { + const currentTarget = event.currentTarget; + + // Give browser time to focus the next element + requestAnimationFrame(() => { + // Check if the new focused element is a child of the original container + if (!currentTarget.contains(document.activeElement)) { + console.log('blurrin yo'); + } + }); + }; } function instanceOfBulkActionListSectionArray( From 2553e7cf9a18019c2faf3cbb868baa375fe06fe6 Mon Sep 17 00:00:00 2001 From: Marc Thomas Date: Tue, 4 Oct 2022 20:04:08 +0100 Subject: [PATCH 05/32] chore: use intersection observer to place bulk actions bar correctly in the DOM --- .../components/BulkActions/BulkActions.tsx | 44 +----------- .../src/components/IndexTable/IndexTable.scss | 12 +++- .../IndexTable/IndexTable.stories.tsx | 44 ++++++------ .../src/components/IndexTable/IndexTable.tsx | 25 +++++-- .../components/Cell/tests/Cell.test.tsx | 9 +++ .../Checkbox/tests/Checkbox.test.tsx | 9 +++ .../components/Row/tests/Row.test.tsx | 9 +++ .../src/components/IndexTable/hooks/index.ts | 1 + .../hooks/use-is-bulk-actions-sticky.ts | 70 +++++++++++++++++++ .../IndexTable/tests/IndexTable.test.tsx | 9 +++ .../SelectAllActions/SelectAllActions.tsx | 8 ++- .../tests/hooks-useContainerScroll.test.tsx | 12 ++++ .../tests/hooks-useRowHovered.test.tsx | 12 ++++ .../tests/hooks-useRowSelected.test.tsx | 12 ++++ 14 files changed, 202 insertions(+), 74 deletions(-) create mode 100644 polaris-react/src/components/IndexTable/hooks/index.ts create mode 100644 polaris-react/src/components/IndexTable/hooks/use-is-bulk-actions-sticky.ts diff --git a/polaris-react/src/components/BulkActions/BulkActions.tsx b/polaris-react/src/components/BulkActions/BulkActions.tsx index eb54ab43c92..049c447c6d2 100644 --- a/polaris-react/src/components/BulkActions/BulkActions.tsx +++ b/polaris-react/src/components/BulkActions/BulkActions.tsx @@ -5,7 +5,6 @@ import {debounce} from '../../utilities/debounce'; import {classNames} from '../../utilities/css'; import {useI18n} from '../../utilities/i18n'; import {clamp} from '../../utilities/clamp'; -import {findFirstKeyboardFocusableNode} from '../../utilities/focus'; import type { BadgeAction, DisableableAction, @@ -64,7 +63,6 @@ class BulkActionsInner extends PureComponent { private containerNode: HTMLElement | null = null; private buttonsNode: HTMLElement | null = null; private moreActionsNode: HTMLElement | null = null; - private activatorNode: Element | null = null; private groupNode = createRef(); private promotedActionsWidths: number[] = []; private bulkActionsWidth = 0; @@ -91,25 +89,6 @@ class BulkActionsInner extends PureComponent { {trailing: true}, ); - private focusContent() { - if (this.containerNode == null) { - return; - } - - requestAnimationFrame(() => { - if (this.containerNode == null) { - return; - } - - const focusableChild = findFirstKeyboardFocusableNode(this.containerNode); - if (focusableChild) { - focusableChild.focus({ - preventScroll: process.env.NODE_ENV === 'development', - }); - } - }); - } - private numberOfPromotedActionsToRender(): number { const {promotedActions} = this.props; const {containerWidth, measuring} = this.state; @@ -199,11 +178,6 @@ class BulkActionsInner extends PureComponent { this.addedMoreActionsWidthForMeasuring : 0; - if (document?.activeElement) { - this.activatorNode = document.activeElement; - } - this.focusContent(); - if (this.containerNode) { this.setState({ containerWidth: this.containerNode.getBoundingClientRect().width, @@ -347,11 +321,7 @@ class BulkActionsInner extends PureComponent {
); - return ( -
- {group} -
- ); + return
{group}
; } private isNewBadgeInBadgeActions() { @@ -395,18 +365,6 @@ class BulkActionsInner extends PureComponent { this.promotedActionsWidths.push(width); } }; - - private handleBlur = (event: React.FocusEvent) => { - const currentTarget = event.currentTarget; - - // Give browser time to focus the next element - requestAnimationFrame(() => { - // Check if the new focused element is a child of the original container - if (!currentTarget.contains(document.activeElement)) { - console.log('blurrin yo'); - } - }); - }; } function instanceOfBulkActionListSectionArray( diff --git a/polaris-react/src/components/IndexTable/IndexTable.scss b/polaris-react/src/components/IndexTable/IndexTable.scss index 55f123466dc..3531659ecbb 100644 --- a/polaris-react/src/components/IndexTable/IndexTable.scss +++ b/polaris-react/src/components/IndexTable/IndexTable.scss @@ -14,7 +14,8 @@ } .IndexTableWithBulkActions { - padding-bottom: var(--p-space-4); + --pc-index-table-bulk-actions-offset: 100px; + padding-bottom: var(--pc-index-table-bulk-actions-offset); } .LoadingContainer-enter { @@ -489,10 +490,9 @@ $loading-panel-height: 53px; .BulkActionsWrapper { visibility: visible; - position: sticky; + position: absolute; z-index: var(--pc-index-table-bulk-actions); left: 0; - bottom: var(--p-space-4); width: 100%; display: flex; align-items: center; @@ -500,6 +500,12 @@ $loading-panel-height: 53px; margin-top: var(--p-space-4); } +.BulkActionsWrapperSticky { + position: fixed; + top: auto; + bottom: var(--p-space-4); +} + .SelectAllActionsWrapper { visibility: visible; position: relative; diff --git a/polaris-react/src/components/IndexTable/IndexTable.stories.tsx b/polaris-react/src/components/IndexTable/IndexTable.stories.tsx index f457b79cbe9..f61994c8441 100644 --- a/polaris-react/src/components/IndexTable/IndexTable.stories.tsx +++ b/polaris-react/src/components/IndexTable/IndexTable.stories.tsx @@ -579,27 +579,29 @@ export function WithBulkActionsAndSelectionAcrossPages() { ); return ( - - - {rowMarkup} - - +
+ + + {rowMarkup} + + +
); } diff --git a/polaris-react/src/components/IndexTable/IndexTable.tsx b/polaris-react/src/components/IndexTable/IndexTable.tsx index ef7cae240d8..b836f4dd820 100644 --- a/polaris-react/src/components/IndexTable/IndexTable.tsx +++ b/polaris-react/src/components/IndexTable/IndexTable.tsx @@ -38,6 +38,7 @@ import type {NonEmptyArray} from '../../types'; import {getTableHeadingsBySelector} from './utilities'; import {ScrollContainer, Cell, Row} from './components'; +import {useIsBulkActionsSticky} from './hooks/use-is-bulk-actions-sticky'; import styles from './IndexTable.scss'; interface IndexTableHeadingBase { @@ -166,6 +167,12 @@ function IndexTableBase({ const scrollContainerElement = useRef(null); const scrollingWithBar = useRef(false); const scrollingContainer = useRef(false); + const { + bulkActionsIntersectionRef, + tableMeasurerRef, + isBulkActionsSticky, + bulkActionsAbsoluteOffset, + } = useIsBulkActionsSticky(); const tableBodyRef = useCallback( (node: Element | null) => { @@ -545,14 +552,23 @@ function IndexTableBase({ const shouldShowBulkActions = (bulkActionsSelectable && selectedItemsCount) || isSmallScreenSelectable; - const bulkActionClassNames = classNames(styles.BulkActionsWrapper); + const bulkActionClassNames = classNames( + styles.BulkActionsWrapper, + isBulkActionsSticky && styles.BulkActionsWrapperSticky, + ); const shouldShowActions = !condensed || selectedItemsCount; const promotedActions = shouldShowActions ? promotedBulkActions : []; const actions = shouldShowActions ? bulkActions : []; const bulkActionsMarkup = shouldShowBulkActions ? ( -
+
{loadingMarkup} + {bulkActionsMarkup}
); @@ -754,11 +771,11 @@ function IndexTableBase({ return ( <>
-
+
{!shouldShowBulkActions && !condensed && loadingMarkup} {tableContentMarkup} - {bulkActionsMarkup}
+
{scrollBarMarkup} diff --git a/polaris-react/src/components/IndexTable/components/Cell/tests/Cell.test.tsx b/polaris-react/src/components/IndexTable/components/Cell/tests/Cell.test.tsx index 32d420ebfa3..e7e8c1c728c 100644 --- a/polaris-react/src/components/IndexTable/components/Cell/tests/Cell.test.tsx +++ b/polaris-react/src/components/IndexTable/components/Cell/tests/Cell.test.tsx @@ -3,6 +3,15 @@ import {mountWithApp} from 'tests/utilities'; import {Cell} from '../Cell'; +jest.mock('../../../hooks/use-is-bulk-actions-sticky', () => ({ + useIsBulkActionsSticky: () => ({ + bulkActionsIntersectionRef: null, + tableMeasurerRef: null, + isBulkActionsSticky: false, + bulkActionsAbsoluteOffset: 0, + }), +})); + describe('', () => { it('renders a table data tag', () => { const cell = mountWithTable(); diff --git a/polaris-react/src/components/IndexTable/components/Checkbox/tests/Checkbox.test.tsx b/polaris-react/src/components/IndexTable/components/Checkbox/tests/Checkbox.test.tsx index 9c4d853732a..2b78dfd760a 100644 --- a/polaris-react/src/components/IndexTable/components/Checkbox/tests/Checkbox.test.tsx +++ b/polaris-react/src/components/IndexTable/components/Checkbox/tests/Checkbox.test.tsx @@ -16,6 +16,15 @@ jest.mock('../../../../../utilities/debounce', () => ({ debounce: (callback: () => void) => () => callback(), })); +jest.mock('../../../hooks/use-is-bulk-actions-sticky', () => ({ + useIsBulkActionsSticky: () => ({ + bulkActionsIntersectionRef: null, + tableMeasurerRef: null, + isBulkActionsSticky: false, + bulkActionsAbsoluteOffset: 0, + }), +})); + describe('', () => { let getBoundingClientRectSpy: jest.SpyInstance; let setRootPropertySpy: jest.SpyInstance; diff --git a/polaris-react/src/components/IndexTable/components/Row/tests/Row.test.tsx b/polaris-react/src/components/IndexTable/components/Row/tests/Row.test.tsx index a9ac9e5c98b..1344e3382ed 100644 --- a/polaris-react/src/components/IndexTable/components/Row/tests/Row.test.tsx +++ b/polaris-react/src/components/IndexTable/components/Row/tests/Row.test.tsx @@ -9,6 +9,15 @@ import {Checkbox} from '../../Checkbox'; import {Button} from '../../../../Button'; import {Link} from '../../../../Link'; +jest.mock('../../../hooks/use-is-bulk-actions-sticky', () => ({ + useIsBulkActionsSticky: () => ({ + bulkActionsIntersectionRef: null, + tableMeasurerRef: null, + isBulkActionsSticky: false, + bulkActionsAbsoluteOffset: 0, + }), +})); + const defaultEvent = { preventDefault: noop, stopPropagation: noop, diff --git a/polaris-react/src/components/IndexTable/hooks/index.ts b/polaris-react/src/components/IndexTable/hooks/index.ts new file mode 100644 index 00000000000..90f7c0a6a8b --- /dev/null +++ b/polaris-react/src/components/IndexTable/hooks/index.ts @@ -0,0 +1 @@ +export {useIsBulkActionsSticky} from './use-is-bulk-actions-sticky'; diff --git a/polaris-react/src/components/IndexTable/hooks/use-is-bulk-actions-sticky.ts b/polaris-react/src/components/IndexTable/hooks/use-is-bulk-actions-sticky.ts new file mode 100644 index 00000000000..c9114ed5e9a --- /dev/null +++ b/polaris-react/src/components/IndexTable/hooks/use-is-bulk-actions-sticky.ts @@ -0,0 +1,70 @@ +import {useEffect, useRef, useState} from 'react'; + +import {debounce} from '../../../utilities/debounce'; + +const DEBOUNCE_PERIOD = 250; + +export function useIsBulkActionsSticky() { + const [isBulkActionsSticky, setIsSticky] = useState(false); + const [bulkActionsAbsoluteOffset, setBulkActionsAbsoluteOffset] = useState(0); + const bulkActionsIntersectionRef = useRef(null); + const tableMeasurerRef = useRef(null); + + useEffect(() => { + function computeTableHeight() { + const node = tableMeasurerRef.current; + if (!node) { + return 0; + } + return node.getBoundingClientRect().height; + } + const tableHeight = computeTableHeight(); + + const debouncedComputeTableHeight = debounce( + computeTableHeight, + DEBOUNCE_PERIOD, + { + trailing: true, + }, + ); + + setBulkActionsAbsoluteOffset(tableHeight); + + window.addEventListener('resize', debouncedComputeTableHeight); + + return () => + window.removeEventListener('resize', debouncedComputeTableHeight); + }, [tableMeasurerRef]); + + useEffect(() => { + const handleIntersect = (entries: IntersectionObserverEntry[]) => { + entries.forEach((entry: IntersectionObserverEntry) => { + setIsSticky(!entry.isIntersecting); + }); + }; + + const options = { + root: null, + rootMargin: '0px', + threshold: 1, + }; + const observer = new IntersectionObserver(handleIntersect, options); + + const node = bulkActionsIntersectionRef.current; + + if (node) { + observer.observe(node); + } + + return () => { + observer.disconnect(); + }; + }, [bulkActionsIntersectionRef]); + + return { + bulkActionsIntersectionRef, + tableMeasurerRef, + isBulkActionsSticky, + bulkActionsAbsoluteOffset, + }; +} diff --git a/polaris-react/src/components/IndexTable/tests/IndexTable.test.tsx b/polaris-react/src/components/IndexTable/tests/IndexTable.test.tsx index f928f15e7a6..51814454bc2 100644 --- a/polaris-react/src/components/IndexTable/tests/IndexTable.test.tsx +++ b/polaris-react/src/components/IndexTable/tests/IndexTable.test.tsx @@ -34,6 +34,15 @@ jest.mock('../../../utilities/debounce', () => ({ }, })); +jest.mock('../hooks/use-is-bulk-actions-sticky', () => ({ + useIsBulkActionsSticky: () => ({ + bulkActionsIntersectionRef: null, + tableMeasurerRef: null, + isBulkActionsSticky: false, + bulkActionsAbsoluteOffset: 0, + }), +})); + const mockTableItems = [ { id: 'item-1', diff --git a/polaris-react/src/components/SelectAllActions/SelectAllActions.tsx b/polaris-react/src/components/SelectAllActions/SelectAllActions.tsx index a30a3b96b45..fc36d05b2e6 100644 --- a/polaris-react/src/components/SelectAllActions/SelectAllActions.tsx +++ b/polaris-react/src/components/SelectAllActions/SelectAllActions.tsx @@ -47,7 +47,6 @@ export function SelectAllActions({ @@ -72,7 +71,6 @@ export function SelectAllActions({ selectMode, onToggleAll, disabled, - plain: !smallScreen, autoWidth: true, ariaLive, }; @@ -85,7 +83,11 @@ export function SelectAllActions({ ); return (
- + {smallScreen ? ( + + ) : ( + + )} {paginatedSelectAllMarkup}
); diff --git a/polaris-react/src/utilities/index-table/tests/hooks-useContainerScroll.test.tsx b/polaris-react/src/utilities/index-table/tests/hooks-useContainerScroll.test.tsx index 6f8b382bdef..810c8ec6e03 100644 --- a/polaris-react/src/utilities/index-table/tests/hooks-useContainerScroll.test.tsx +++ b/polaris-react/src/utilities/index-table/tests/hooks-useContainerScroll.test.tsx @@ -9,6 +9,18 @@ import { } from '../../../components/IndexTable'; import {useContainerScroll} from '../hooks'; +jest.mock( + '../../../components/IndexTable/hooks/use-is-bulk-actions-sticky', + () => ({ + useIsBulkActionsSticky: () => ({ + bulkActionsIntersectionRef: null, + tableMeasurerRef: null, + isBulkActionsSticky: false, + bulkActionsAbsoluteOffset: 0, + }), + }), +); + function Component({condensed}: {condensed?: boolean}) { const {scrollableContainer, canScrollLeft, canScrollRight} = useContainerScroll(); diff --git a/polaris-react/src/utilities/index-table/tests/hooks-useRowHovered.test.tsx b/polaris-react/src/utilities/index-table/tests/hooks-useRowHovered.test.tsx index 6b2e2407775..fe9997f745d 100644 --- a/polaris-react/src/utilities/index-table/tests/hooks-useRowHovered.test.tsx +++ b/polaris-react/src/utilities/index-table/tests/hooks-useRowHovered.test.tsx @@ -5,6 +5,18 @@ import {mountWithApp} from 'tests/utilities'; import {IndexTable, IndexTableProps} from '../../../components/IndexTable'; import {useRowHovered} from '../hooks'; +jest.mock( + '../../../components/IndexTable/hooks/use-is-bulk-actions-sticky', + () => ({ + useIsBulkActionsSticky: () => ({ + bulkActionsIntersectionRef: null, + tableMeasurerRef: null, + isBulkActionsSticky: false, + bulkActionsAbsoluteOffset: 0, + }), + }), +); + function Component() { const hovered = useRowHovered(); const content = hovered ? 'In' : 'Out'; diff --git a/polaris-react/src/utilities/index-table/tests/hooks-useRowSelected.test.tsx b/polaris-react/src/utilities/index-table/tests/hooks-useRowSelected.test.tsx index 055a3a5a132..3de8a4df34e 100644 --- a/polaris-react/src/utilities/index-table/tests/hooks-useRowSelected.test.tsx +++ b/polaris-react/src/utilities/index-table/tests/hooks-useRowSelected.test.tsx @@ -5,6 +5,18 @@ import {mountWithApp} from 'tests/utilities'; import {IndexTable, IndexTableProps} from '../../../components/IndexTable'; import {useRowSelected} from '../hooks'; +jest.mock( + '../../../components/IndexTable/hooks/use-is-bulk-actions-sticky', + () => ({ + useIsBulkActionsSticky: () => ({ + bulkActionsIntersectionRef: null, + tableMeasurerRef: null, + isBulkActionsSticky: false, + bulkActionsAbsoluteOffset: 0, + }), + }), +); + function Component() { const selected = useRowSelected(); const content = selected ? 'Selected' : 'Unselected'; From da47ecb307a0954c6107d574395568dfa475d2bc Mon Sep 17 00:00:00 2001 From: Marc Thomas Date: Fri, 7 Oct 2022 12:29:25 +0100 Subject: [PATCH 06/32] chore: add tests to new hook --- .../hooks/index.ts | 0 .../tests/use-is-bulk-actions-sticky.test.tsx | 112 ++++++++++++++++++ .../hooks/use-is-bulk-actions-sticky.ts | 13 +- .../src/components/BulkActions/index.ts | 1 + .../src/components/IndexTable/IndexTable.tsx | 13 +- .../components/Cell/tests/Cell.test.tsx | 9 -- .../Checkbox/tests/Checkbox.test.tsx | 9 -- .../components/Row/tests/Row.test.tsx | 9 -- .../IndexTable/tests/IndexTable.test.tsx | 3 +- .../components/ResourceList/ResourceList.scss | 12 +- .../components/ResourceList/ResourceList.tsx | 29 ++++- .../ResourceList/tests/ResourceList.test.tsx | 10 ++ .../tests/hooks-useContainerScroll.test.tsx | 12 -- .../tests/hooks-useRowHovered.test.tsx | 12 -- .../tests/hooks-useRowSelected.test.tsx | 12 -- 15 files changed, 178 insertions(+), 78 deletions(-) rename polaris-react/src/components/{IndexTable => BulkActions}/hooks/index.ts (100%) create mode 100644 polaris-react/src/components/BulkActions/hooks/tests/use-is-bulk-actions-sticky.test.tsx rename polaris-react/src/components/{IndexTable => BulkActions}/hooks/use-is-bulk-actions-sticky.ts (81%) diff --git a/polaris-react/src/components/IndexTable/hooks/index.ts b/polaris-react/src/components/BulkActions/hooks/index.ts similarity index 100% rename from polaris-react/src/components/IndexTable/hooks/index.ts rename to polaris-react/src/components/BulkActions/hooks/index.ts diff --git a/polaris-react/src/components/BulkActions/hooks/tests/use-is-bulk-actions-sticky.test.tsx b/polaris-react/src/components/BulkActions/hooks/tests/use-is-bulk-actions-sticky.test.tsx new file mode 100644 index 00000000000..52cb3f4ddcc --- /dev/null +++ b/polaris-react/src/components/BulkActions/hooks/tests/use-is-bulk-actions-sticky.test.tsx @@ -0,0 +1,112 @@ +import React from 'react'; +import {intersectionObserver} from '@shopify/jest-dom-mocks'; +import {mountWithApp} from 'tests/utilities'; + +import {useIsBulkActionsSticky} from '..'; + +interface ComponentProps { + selectMode: boolean; +} + +function Component({selectMode}: ComponentProps) { + const { + bulkActionsIntersectionRef, + tableMeasurerRef, + isBulkActionsSticky, + bulkActionsAbsoluteOffset, + } = useIsBulkActionsSticky(selectMode); + + return ( +
+

{isBulkActionsSticky ? 'true' : 'false'}

+ {bulkActionsAbsoluteOffset} + + +
+ ); +} + +describe('useIsBulkActionsSticky', () => { + let getBoundingClientRectSpy: jest.SpyInstance; + + beforeEach(() => { + getBoundingClientRectSpy = jest.spyOn( + Element.prototype, + 'getBoundingClientRect', + ); + setGetBoundingClientRect(400); + + intersectionObserver.mock(); + }); + + afterEach(() => { + getBoundingClientRectSpy.mockRestore(); + intersectionObserver.restore(); + }); + + describe('when measuring', () => { + it('returns the offset correctly when select mode is false', () => { + const component = mountWithApp(); + const result = component.find('span')?.text(); + expect(result).toBe('400'); + }); + + it('returns the offset correctly when select mode is true', () => { + const component = mountWithApp(); + const result = component.find('span')?.text(); + expect(result).toBe('300'); + }); + }); + + describe('when isIntersecting', () => { + it('sets the isBulkActionsSticky value to false', () => { + const component = mountWithApp(); + + const intersector = component.find('i'); + + component.act(() => { + intersectionObserver.simulate({ + isIntersecting: true, + target: intersector!.domNode!, + }); + }); + + const result = component.find('p')?.text(); + expect(result).toBe('false'); + }); + }); + + describe('when not isIntersecting', () => { + it('sets the isBulkActionsSticky value to true', () => { + const component = mountWithApp(); + + const intersector = component.find('i'); + + component.act(() => { + intersectionObserver.simulate({ + isIntersecting: false, + target: intersector!.domNode!, + }); + }); + + const result = component.find('p')?.text(); + expect(result).toBe('true'); + }); + }); + + function setGetBoundingClientRect(height: number) { + getBoundingClientRectSpy.mockImplementation(() => { + return { + height, + width: 0, + top: 0, + left: 0, + bottom: 0, + right: 0, + x: 0, + y: 0, + toJSON() {}, + }; + }); + } +}); diff --git a/polaris-react/src/components/IndexTable/hooks/use-is-bulk-actions-sticky.ts b/polaris-react/src/components/BulkActions/hooks/use-is-bulk-actions-sticky.ts similarity index 81% rename from polaris-react/src/components/IndexTable/hooks/use-is-bulk-actions-sticky.ts rename to polaris-react/src/components/BulkActions/hooks/use-is-bulk-actions-sticky.ts index c9114ed5e9a..5dc4c52d67b 100644 --- a/polaris-react/src/components/IndexTable/hooks/use-is-bulk-actions-sticky.ts +++ b/polaris-react/src/components/BulkActions/hooks/use-is-bulk-actions-sticky.ts @@ -4,7 +4,9 @@ import {debounce} from '../../../utilities/debounce'; const DEBOUNCE_PERIOD = 250; -export function useIsBulkActionsSticky() { +const PADDING_IN_SELECT_MODE = 100; + +export function useIsBulkActionsSticky(selectMode: boolean) { const [isBulkActionsSticky, setIsSticky] = useState(false); const [bulkActionsAbsoluteOffset, setBulkActionsAbsoluteOffset] = useState(0); const bulkActionsIntersectionRef = useRef(null); @@ -16,7 +18,8 @@ export function useIsBulkActionsSticky() { if (!node) { return 0; } - return node.getBoundingClientRect().height; + const paddingHeight = selectMode ? PADDING_IN_SELECT_MODE : 0; + return node.getBoundingClientRect().height - paddingHeight; } const tableHeight = computeTableHeight(); @@ -34,9 +37,13 @@ export function useIsBulkActionsSticky() { return () => window.removeEventListener('resize', debouncedComputeTableHeight); - }, [tableMeasurerRef]); + }, [tableMeasurerRef, selectMode]); useEffect(() => { + const hasIOSupport = Boolean(IntersectionObserver); + if (!hasIOSupport) { + return; + } const handleIntersect = (entries: IntersectionObserverEntry[]) => { entries.forEach((entry: IntersectionObserverEntry) => { setIsSticky(!entry.isIntersecting); diff --git a/polaris-react/src/components/BulkActions/index.ts b/polaris-react/src/components/BulkActions/index.ts index a8609f672d6..6235b15b959 100644 --- a/polaris-react/src/components/BulkActions/index.ts +++ b/polaris-react/src/components/BulkActions/index.ts @@ -1 +1,2 @@ export * from './BulkActions'; +export * from './hooks'; diff --git a/polaris-react/src/components/IndexTable/IndexTable.tsx b/polaris-react/src/components/IndexTable/IndexTable.tsx index b836f4dd820..7a73392ce90 100644 --- a/polaris-react/src/components/IndexTable/IndexTable.tsx +++ b/polaris-react/src/components/IndexTable/IndexTable.tsx @@ -23,7 +23,11 @@ import {Text} from '../Text'; import {Button} from '../Button'; import {Tooltip} from '../Tooltip'; import {UnstyledButton} from '../UnstyledButton'; -import {BulkActions, BulkActionsProps} from '../BulkActions'; +import { + BulkActions, + BulkActionsProps, + useIsBulkActionsSticky, +} from '../BulkActions'; import {classNames} from '../../utilities/css'; import { useIndexValue, @@ -38,7 +42,6 @@ import type {NonEmptyArray} from '../../types'; import {getTableHeadingsBySelector} from './utilities'; import {ScrollContainer, Cell, Row} from './components'; -import {useIsBulkActionsSticky} from './hooks/use-is-bulk-actions-sticky'; import styles from './IndexTable.scss'; interface IndexTableHeadingBase { @@ -172,7 +175,7 @@ function IndexTableBase({ tableMeasurerRef, isBulkActionsSticky, bulkActionsAbsoluteOffset, - } = useIsBulkActionsSticky(); + } = useIsBulkActionsSticky(selectMode); const tableBodyRef = useCallback( (node: Element | null) => { @@ -762,7 +765,7 @@ function IndexTableBase({
{emptyStateMarkup}
); - const bulkActionsWrapperClassNames = classNames( + const tableWrapperClassNames = classNames( Boolean(bulkActionsMarkup) && selectMode && styles.IndexTableWithBulkActions, @@ -771,7 +774,7 @@ function IndexTableBase({ return ( <>
-
+
{!shouldShowBulkActions && !condensed && loadingMarkup} {tableContentMarkup}
diff --git a/polaris-react/src/components/IndexTable/components/Cell/tests/Cell.test.tsx b/polaris-react/src/components/IndexTable/components/Cell/tests/Cell.test.tsx index e7e8c1c728c..32d420ebfa3 100644 --- a/polaris-react/src/components/IndexTable/components/Cell/tests/Cell.test.tsx +++ b/polaris-react/src/components/IndexTable/components/Cell/tests/Cell.test.tsx @@ -3,15 +3,6 @@ import {mountWithApp} from 'tests/utilities'; import {Cell} from '../Cell'; -jest.mock('../../../hooks/use-is-bulk-actions-sticky', () => ({ - useIsBulkActionsSticky: () => ({ - bulkActionsIntersectionRef: null, - tableMeasurerRef: null, - isBulkActionsSticky: false, - bulkActionsAbsoluteOffset: 0, - }), -})); - describe('', () => { it('renders a table data tag', () => { const cell = mountWithTable(); diff --git a/polaris-react/src/components/IndexTable/components/Checkbox/tests/Checkbox.test.tsx b/polaris-react/src/components/IndexTable/components/Checkbox/tests/Checkbox.test.tsx index 2b78dfd760a..9c4d853732a 100644 --- a/polaris-react/src/components/IndexTable/components/Checkbox/tests/Checkbox.test.tsx +++ b/polaris-react/src/components/IndexTable/components/Checkbox/tests/Checkbox.test.tsx @@ -16,15 +16,6 @@ jest.mock('../../../../../utilities/debounce', () => ({ debounce: (callback: () => void) => () => callback(), })); -jest.mock('../../../hooks/use-is-bulk-actions-sticky', () => ({ - useIsBulkActionsSticky: () => ({ - bulkActionsIntersectionRef: null, - tableMeasurerRef: null, - isBulkActionsSticky: false, - bulkActionsAbsoluteOffset: 0, - }), -})); - describe('', () => { let getBoundingClientRectSpy: jest.SpyInstance; let setRootPropertySpy: jest.SpyInstance; diff --git a/polaris-react/src/components/IndexTable/components/Row/tests/Row.test.tsx b/polaris-react/src/components/IndexTable/components/Row/tests/Row.test.tsx index 1344e3382ed..a9ac9e5c98b 100644 --- a/polaris-react/src/components/IndexTable/components/Row/tests/Row.test.tsx +++ b/polaris-react/src/components/IndexTable/components/Row/tests/Row.test.tsx @@ -9,15 +9,6 @@ import {Checkbox} from '../../Checkbox'; import {Button} from '../../../../Button'; import {Link} from '../../../../Link'; -jest.mock('../../../hooks/use-is-bulk-actions-sticky', () => ({ - useIsBulkActionsSticky: () => ({ - bulkActionsIntersectionRef: null, - tableMeasurerRef: null, - isBulkActionsSticky: false, - bulkActionsAbsoluteOffset: 0, - }), -})); - const defaultEvent = { preventDefault: noop, stopPropagation: noop, diff --git a/polaris-react/src/components/IndexTable/tests/IndexTable.test.tsx b/polaris-react/src/components/IndexTable/tests/IndexTable.test.tsx index 51814454bc2..647834f4642 100644 --- a/polaris-react/src/components/IndexTable/tests/IndexTable.test.tsx +++ b/polaris-react/src/components/IndexTable/tests/IndexTable.test.tsx @@ -34,7 +34,8 @@ jest.mock('../../../utilities/debounce', () => ({ }, })); -jest.mock('../hooks/use-is-bulk-actions-sticky', () => ({ +jest.mock('../../BulkActions', () => ({ + ...jest.requireActual('../../BulkActions'), useIsBulkActionsSticky: () => ({ bulkActionsIntersectionRef: null, tableMeasurerRef: null, diff --git a/polaris-react/src/components/ResourceList/ResourceList.scss b/polaris-react/src/components/ResourceList/ResourceList.scss index 06363732b94..33d52d97c29 100644 --- a/polaris-react/src/components/ResourceList/ResourceList.scss +++ b/polaris-react/src/components/ResourceList/ResourceList.scss @@ -157,8 +157,7 @@ $breakpoints-empty-search-results-height-up: '(min-height: #{breakpoint(600px)}) .BulkActionsWrapper { z-index: resource-list(bulk-actions-wrapper-stacking-order); visibility: visible; - position: sticky; - bottom: var(--p-space-4); + position: absolute; left: 0; width: 100%; display: flex; @@ -172,6 +171,12 @@ $breakpoints-empty-search-results-height-up: '(min-height: #{breakpoint(600px)}) } } +.BulkActionsWrapperSticky { + position: fixed; + top: auto; + bottom: var(--p-space-4); +} + .SelectAllActionsWrapper { position: relative; z-index: resource-list(bulk-actions-wrapper-stacking-order); @@ -217,7 +222,8 @@ $breakpoints-empty-search-results-height-up: '(min-height: #{breakpoint(600px)}) } .ResourceListWrapperWithBulkActions { - padding-bottom: var(--p-space-4); + --pc-resource-list-bulk-actions-offset: 100px; + padding-bottom: var(--pc-resource-list-bulk-actions-offset); } .ResourceList { diff --git a/polaris-react/src/components/ResourceList/ResourceList.tsx b/polaris-react/src/components/ResourceList/ResourceList.tsx index 74761a4a241..cb0dfc7550c 100644 --- a/polaris-react/src/components/ResourceList/ResourceList.tsx +++ b/polaris-react/src/components/ResourceList/ResourceList.tsx @@ -31,7 +31,11 @@ import {EmptySearchResult} from '../EmptySearchResult'; import {useI18n} from '../../utilities/i18n'; import {ResourceItem} from '../ResourceItem'; import {useLazyRef} from '../../utilities/use-lazy-ref'; -import {BulkActions, BulkActionsProps} from '../BulkActions'; +import { + BulkActions, + BulkActionsProps, + useIsBulkActionsSticky, +} from '../BulkActions'; import {SelectAllActions} from '../SelectAllActions'; import {CheckableButton} from '../CheckableButton'; @@ -162,6 +166,13 @@ export const ResourceList: ResourceListType = function ResourceList({ new Map(), ); + const { + bulkActionsIntersectionRef, + tableMeasurerRef, + isBulkActionsSticky, + bulkActionsAbsoluteOffset, + } = useIsBulkActionsSticky(selectMode); + const defaultResourceName = useLazyRef(() => ({ singular: i18n.translate('Polaris.ResourceList.defaultItemSingular'), plural: i18n.translate('Polaris.ResourceList.defaultItemPlural'), @@ -550,8 +561,18 @@ export const ResourceList: ResourceListType = function ResourceList({
) : null; + const bulkActionClassNames = classNames( + styles.BulkActionsWrapper, + isBulkActionsSticky && styles.BulkActionsWrapperSticky, + ); + const bulkActionsMarkup = isSelectable ? ( -
+
({ ); }} + {bulkActionsMarkup}
); @@ -742,6 +764,7 @@ export const ResourceList: ResourceListType = function ResourceList({ selectMode && styles.ResourceListWrapperWithBulkActions, )} + ref={tableMeasurerRef} > {filterControlMarkup} {headerMarkup} @@ -749,8 +772,8 @@ export const ResourceList: ResourceListType = function ResourceList({ {emptySearchStateMarkup} {emptyStateMarkup} {loadingWithoutItemsMarkup} - {bulkActionsMarkup}
+
); }; diff --git a/polaris-react/src/components/ResourceList/tests/ResourceList.test.tsx b/polaris-react/src/components/ResourceList/tests/ResourceList.test.tsx index a0bd3c114c4..0abaa1cf91b 100644 --- a/polaris-react/src/components/ResourceList/tests/ResourceList.test.tsx +++ b/polaris-react/src/components/ResourceList/tests/ResourceList.test.tsx @@ -16,6 +16,16 @@ import {SELECT_ALL_ITEMS} from '../../../utilities/resource-list'; import {ResourceList} from '../ResourceList'; import styles from '../ResourceList.scss'; +jest.mock('../../BulkActions', () => ({ + ...jest.requireActual('../../BulkActions'), + useIsBulkActionsSticky: () => ({ + bulkActionsIntersectionRef: null, + tableMeasurerRef: null, + isBulkActionsSticky: false, + bulkActionsAbsoluteOffset: 0, + }), +})); + const itemsNoID = [{url: 'item 1'}, {url: 'item 2'}]; const singleItemNoID = [{url: 'item 1'}]; const singleItemWithID = [{id: '1', url: 'item 1'}]; diff --git a/polaris-react/src/utilities/index-table/tests/hooks-useContainerScroll.test.tsx b/polaris-react/src/utilities/index-table/tests/hooks-useContainerScroll.test.tsx index 810c8ec6e03..6f8b382bdef 100644 --- a/polaris-react/src/utilities/index-table/tests/hooks-useContainerScroll.test.tsx +++ b/polaris-react/src/utilities/index-table/tests/hooks-useContainerScroll.test.tsx @@ -9,18 +9,6 @@ import { } from '../../../components/IndexTable'; import {useContainerScroll} from '../hooks'; -jest.mock( - '../../../components/IndexTable/hooks/use-is-bulk-actions-sticky', - () => ({ - useIsBulkActionsSticky: () => ({ - bulkActionsIntersectionRef: null, - tableMeasurerRef: null, - isBulkActionsSticky: false, - bulkActionsAbsoluteOffset: 0, - }), - }), -); - function Component({condensed}: {condensed?: boolean}) { const {scrollableContainer, canScrollLeft, canScrollRight} = useContainerScroll(); diff --git a/polaris-react/src/utilities/index-table/tests/hooks-useRowHovered.test.tsx b/polaris-react/src/utilities/index-table/tests/hooks-useRowHovered.test.tsx index fe9997f745d..6b2e2407775 100644 --- a/polaris-react/src/utilities/index-table/tests/hooks-useRowHovered.test.tsx +++ b/polaris-react/src/utilities/index-table/tests/hooks-useRowHovered.test.tsx @@ -5,18 +5,6 @@ import {mountWithApp} from 'tests/utilities'; import {IndexTable, IndexTableProps} from '../../../components/IndexTable'; import {useRowHovered} from '../hooks'; -jest.mock( - '../../../components/IndexTable/hooks/use-is-bulk-actions-sticky', - () => ({ - useIsBulkActionsSticky: () => ({ - bulkActionsIntersectionRef: null, - tableMeasurerRef: null, - isBulkActionsSticky: false, - bulkActionsAbsoluteOffset: 0, - }), - }), -); - function Component() { const hovered = useRowHovered(); const content = hovered ? 'In' : 'Out'; diff --git a/polaris-react/src/utilities/index-table/tests/hooks-useRowSelected.test.tsx b/polaris-react/src/utilities/index-table/tests/hooks-useRowSelected.test.tsx index 3de8a4df34e..055a3a5a132 100644 --- a/polaris-react/src/utilities/index-table/tests/hooks-useRowSelected.test.tsx +++ b/polaris-react/src/utilities/index-table/tests/hooks-useRowSelected.test.tsx @@ -5,18 +5,6 @@ import {mountWithApp} from 'tests/utilities'; import {IndexTable, IndexTableProps} from '../../../components/IndexTable'; import {useRowSelected} from '../hooks'; -jest.mock( - '../../../components/IndexTable/hooks/use-is-bulk-actions-sticky', - () => ({ - useIsBulkActionsSticky: () => ({ - bulkActionsIntersectionRef: null, - tableMeasurerRef: null, - isBulkActionsSticky: false, - bulkActionsAbsoluteOffset: 0, - }), - }), -); - function Component() { const selected = useRowSelected(); const content = selected ? 'Selected' : 'Unselected'; From 9d22b6af8d5fe43fa4287d574741a02e852b0980 Mon Sep 17 00:00:00 2001 From: Marc Thomas Date: Fri, 7 Oct 2022 13:36:15 +0100 Subject: [PATCH 07/32] chore: remove condensde UI for BulkActions and SelectAllActions --- .../hooks/use-is-bulk-actions-sticky.ts | 2 +- .../IndexTable/IndexTable.stories.tsx | 92 +++++++++++++++---- .../src/components/IndexTable/IndexTable.tsx | 43 ++------- .../IndexTable/tests/IndexTable.test.tsx | 58 +----------- .../components/ResourceList/ResourceList.tsx | 13 +-- .../ResourceList/tests/ResourceList.test.tsx | 41 +-------- 6 files changed, 98 insertions(+), 151 deletions(-) diff --git a/polaris-react/src/components/BulkActions/hooks/use-is-bulk-actions-sticky.ts b/polaris-react/src/components/BulkActions/hooks/use-is-bulk-actions-sticky.ts index 5dc4c52d67b..bf5e40a2c73 100644 --- a/polaris-react/src/components/BulkActions/hooks/use-is-bulk-actions-sticky.ts +++ b/polaris-react/src/components/BulkActions/hooks/use-is-bulk-actions-sticky.ts @@ -40,7 +40,7 @@ export function useIsBulkActionsSticky(selectMode: boolean) { }, [tableMeasurerRef, selectMode]); useEffect(() => { - const hasIOSupport = Boolean(IntersectionObserver); + const hasIOSupport = Boolean(window.IntersectionObserver); if (!hasIOSupport) { return; } diff --git a/polaris-react/src/components/IndexTable/IndexTable.stories.tsx b/polaris-react/src/components/IndexTable/IndexTable.stories.tsx index f61994c8441..290b6f8a1c8 100644 --- a/polaris-react/src/components/IndexTable/IndexTable.stories.tsx +++ b/polaris-react/src/components/IndexTable/IndexTable.stories.tsx @@ -229,6 +229,79 @@ export function SmallScreen() { ); } +export function SmallScreenLoading() { + const customers = [ + { + id: '3412', + url: 'customers/341', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$2,400', + }, + { + id: '2562', + url: 'customers/256', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + orders: 30, + amountSpent: '$140', + }, + ]; + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(customers); + + const rowMarkup = customers.map( + ({id, name, location, orders, amountSpent}, index) => ( + +
+

+ {name} +

+

{location}

+

{orders}

+

{amountSpent}

+
+
+ ), + ); + + return ( +
+ + + {rowMarkup} + + +
+ ); +} + export function WithEmptyState() { const customers = []; const resourceName = { @@ -511,24 +584,7 @@ export function WithBulkActionsAndSelectionAcrossPages() { amountSpent: '$24,00', }; }); - // const customers = [ - // { - // id: '3414', - // url: 'customers/341', - // name: 'Mae Jemison', - // location: 'Decatur, USA', - // orders: 20, - // amountSpent: '$2,400', - // }, - // { - // id: '2564', - // url: 'customers/256', - // name: 'Ellen Ochoa', - // location: 'Los Angeles, USA', - // orders: 30, - // amountSpent: '$140', - // }, - // ]; + const resourceName = { singular: 'customer', plural: 'customers', diff --git a/polaris-react/src/components/IndexTable/IndexTable.tsx b/polaris-react/src/components/IndexTable/IndexTable.tsx index 7a73392ce90..02b0818630f 100644 --- a/polaris-react/src/components/IndexTable/IndexTable.tsx +++ b/polaris-react/src/components/IndexTable/IndexTable.tsx @@ -1,9 +1,5 @@ import React, {useRef, useState, useEffect, useCallback, useMemo} from 'react'; -import { - EnableSelectionMinor, - SortAscendingMajor, - SortDescendingMajor, -} from '@shopify/polaris-icons'; +import {SortAscendingMajor, SortDescendingMajor} from '@shopify/polaris-icons'; import {CSSTransition} from 'react-transition-group'; import {tokens, toPx, motion} from '@shopify/polaris-tokens'; @@ -20,7 +16,7 @@ import {Stack} from '../Stack'; import {Sticky} from '../Sticky'; import {Spinner} from '../Spinner'; import {Text} from '../Text'; -import {Button} from '../Button'; +import {VisuallyHidden} from '../VisuallyHidden'; import {Tooltip} from '../Tooltip'; import {UnstyledButton} from '../UnstyledButton'; import { @@ -155,7 +151,6 @@ function IndexTableBase({ const condensedListElement = useRef(null); const [tableInitialized, setTableInitialized] = useState(false); - const [isSmallScreenSelectable, setIsSmallScreenSelectable] = useState(false); const [stickyWrapper, setStickyWrapper] = useState(null); const [hideScrollContainer, setHideScrollContainer] = useState(false); @@ -186,10 +181,6 @@ function IndexTableBase({ [tableInitialized], ); - const toggleIsSmallScreenSelectable = useCallback(() => { - setIsSmallScreenSelectable((value) => !value); - }, []); - const handleSelectAllItemsInStore = useCallback(() => { handleSelectionChange( selectedItemsCount === SELECT_ALL_ITEMS @@ -440,12 +431,6 @@ function IndexTableBase({ ); }, [tableInitialized, resizeTableScrollBar, condensed]); - useEffect(() => { - if (!condensed && isSmallScreenSelectable) { - setIsSmallScreenSelectable(false); - } - }, [condensed, isSmallScreenSelectable]); - const hasBulkActions = Boolean( (promotedBulkActions && promotedBulkActions.length > 0) || (bulkActions && bulkActions.length > 0), @@ -552,8 +537,7 @@ function IndexTableBase({ condensed && styles['StickyTable-condensed'], ); - const shouldShowBulkActions = - (bulkActionsSelectable && selectedItemsCount) || isSmallScreenSelectable; + const shouldShowBulkActions = bulkActionsSelectable && selectedItemsCount; const bulkActionClassNames = classNames( styles.BulkActionsWrapper, @@ -575,7 +559,7 @@ function IndexTableBase({ {loadingMarkup} - {i18n.translate('Polaris.IndexTable.selectButtonText')} - - ); - const headerMarkup = condensed ? (
{loadingMarkup} {sort} - {selectable && selectButtonMarkup}
) : (
{sharedMarkup}
    @@ -992,9 +966,8 @@ function IndexTableBase({ }; } - function handleSelectModeToggle(val: boolean) { + function handleSelectModeToggle() { handleSelectionChange(SelectionType.All, false); - setIsSmallScreenSelectable(val); } } diff --git a/polaris-react/src/components/IndexTable/tests/IndexTable.test.tsx b/polaris-react/src/components/IndexTable/tests/IndexTable.test.tsx index 647834f4642..a3e6ed55ba1 100644 --- a/polaris-react/src/components/IndexTable/tests/IndexTable.test.tsx +++ b/polaris-react/src/components/IndexTable/tests/IndexTable.test.tsx @@ -8,7 +8,6 @@ import {EmptySearchResult} from '../../EmptySearchResult'; import {EventListener} from '../../EventListener'; import {Spinner} from '../../Spinner'; import {Sticky} from '../../Sticky'; -import {Button} from '../../Button'; import {Checkbox} from '../../Checkbox'; import {Badge} from '../../Badge'; import {Text} from '../../Text'; @@ -551,30 +550,24 @@ describe('', () => { }); }); - it('renders bulk actions when selectable', () => { + it('does not render bulk actions', () => { const index = mountWithApp( {mockTableItems.map(mockRenderCondensedRow)} , ); - index.find(Button, {children: 'Select'})?.trigger('onClick'); - - expect(index).toContainReactComponent(BulkActions, { - selectMode: true, - }); + expect(index).not.toContainReactComponent(BulkActions); }); - it('does not render a Select button when not selectable', () => { + it('does not render SelectAllActions', () => { const index = mountWithApp( {mockTableItems.map(mockRenderCondensedRow)} , ); - expect(index).not.toContainReactComponent(Button, { - children: 'Select', - }); + expect(index).not.toContainReactComponent(SelectAllActions); }); it('does not render bulk actions with onSelectModeToggle when condensed is false', () => { @@ -594,19 +587,6 @@ describe('', () => { }); }); - it('toggles selectable state when the bulk action button is triggered', () => { - const index = mountWithApp( - - {mockTableItems.map(mockRenderCondensedRow)} - , - ); - - index.find(Button, {children: 'Select'})?.trigger('onClick'); - index.find(BulkActions)?.trigger('onSelectModeToggle'); - - expect(index).not.toContainReactComponent(BulkActions); - }); - it('renders sort markup', () => { const id = 'sort'; const index = mountWithApp( @@ -632,20 +612,7 @@ describe('', () => { expect(index).toContainReactComponent('ul'); }); - it('leaves small screen select mode when going from condensed to regular', () => { - const index = mountWithApp( - - {mockTableItems.map(mockRenderCondensedRow)} - , - ); - - index.find(Button, {children: 'Select'})?.trigger('onClick'); - index.setProps({condensed: false}); - - expect(index).not.toContainReactComponent(BulkActions); - }); - - it('does not render bulk actions with onSelectModeToggle unless items are selected', () => { + it('does not render bulk actions with bulkActions and promotedActions', () => { Object.defineProperty(window, 'innerWidth', { value: 300, }); @@ -666,21 +633,6 @@ describe('', () => { ); expect(index).not.toContainReactComponent(BulkActions); - - index.find(Sticky)!.find(Button)!.trigger('onClick'); - expect(index).toContainReactComponent(BulkActions, { - actions: [], - promotedActions: [], - }); - - index.setProps({ - selectedItemsCount: 2, - }); - - expect(index).toContainReactComponent(BulkActions, { - actions: bulkActions, - promotedActions, - }); }); }); diff --git a/polaris-react/src/components/ResourceList/ResourceList.tsx b/polaris-react/src/components/ResourceList/ResourceList.tsx index cb0dfc7550c..06d4b5dfb7a 100644 --- a/polaris-react/src/components/ResourceList/ResourceList.tsx +++ b/polaris-react/src/components/ResourceList/ResourceList.tsx @@ -206,11 +206,12 @@ export const ResourceList: ResourceListType = function ResourceList({ {leading: true, trailing: true, maxWait: 50}, ); - const isSelectable = Boolean( - (promotedBulkActions && promotedBulkActions.length > 0) || - (bulkActions && bulkActions.length > 0) || - selectable, - ); + const isSelectable = + Boolean( + (promotedBulkActions && promotedBulkActions.length > 0) || + (bulkActions && bulkActions.length > 0) || + selectable, + ) && !smallScreen; const selectAllSelectState = (): boolean | 'indeterminate' => { let selectState: boolean | 'indeterminate' = 'indeterminate'; @@ -671,7 +672,6 @@ export const ResourceList: ResourceListType = function ResourceList({ ); return (
    - {headerWrapperOverlay}
    {headerTitleMarkup} @@ -757,6 +757,7 @@ export const ResourceList: ResourceListType = function ResourceList({ return ( +
    ', () => { setDefaultScreen(); }); - it('keeps focus on the CheckableButton checkbox when selecting', () => { - setSmallScreen(); - - const resourceList = mountWithApp( - , - ); - - resourceList.find(Button)!.trigger('onClick'); - - const selectAllCheckableButton = resourceList - .findAll(CheckableButton) - .find((ele) => !ele.prop('plain'))!; - - selectAllCheckableButton.trigger('onToggleAll'); - - const checkBox = selectAllCheckableButton.find('input', { - type: 'checkbox', - })!; - - expect(document.activeElement).toBe(checkBox.domNode); - }); - - it('keeps focus on the CheckableButton checkbox when deselecting', () => { + it('does not render the selecting UI', () => { setSmallScreen(); const resourceList = mountWithApp( @@ -1051,17 +1025,8 @@ describe('', () => { />, ); - const deselectAllCheckableButton = resourceList - .findAll(CheckableButton) - .find((ele) => !ele.prop('plain'))!; - - deselectAllCheckableButton.trigger('onToggleAll'); - - const checkBox = deselectAllCheckableButton.find('input', { - type: 'checkbox', - })!; - - expect(document.activeElement).toBe(checkBox.domNode); + expect(resourceList).not.toContainReactComponent(SelectAllActions); + expect(resourceList).not.toContainReactComponent(BulkActions); }); }); }); From d93b6748e0c851f334be386b5bad50e7acaa16a3 Mon Sep 17 00:00:00 2001 From: Marc Thomas Date: Fri, 7 Oct 2022 18:17:56 +0100 Subject: [PATCH 08/32] add entrance animations --- .../components/BulkActions/BulkActions.scss | 45 +++++++-------- .../components/BulkActions/BulkActions.tsx | 57 ++++++++++--------- .../src/components/IndexTable/IndexTable.tsx | 1 + 3 files changed, 52 insertions(+), 51 deletions(-) diff --git a/polaris-react/src/components/BulkActions/BulkActions.scss b/polaris-react/src/components/BulkActions/BulkActions.scss index e4ab75cc559..d06199e445d 100644 --- a/polaris-react/src/components/BulkActions/BulkActions.scss +++ b/polaris-react/src/components/BulkActions/BulkActions.scss @@ -7,24 +7,35 @@ $bulk-actions-button-stacking-order: ( .Group { @include text-style-input; - display: none; + display: flex; align-items: center; flex-wrap: wrap; opacity: 0; width: 90vw; justify-content: center; + transition: var(--p-duration-250) var(--p-ease-in); + transform: translateY(120px); - @media #{$p-breakpoints-sm-up} { + &.Group-not-sticky { + transform: none; + opacity: 1; + } + + &.Group-entering, + &.Group-exiting { + opacity: 0; display: flex; + } - &.Group-exiting { - transition: none; - } + &.Group-entered { + opacity: 1; + display: flex; + transform: translateY(0); + } - &.Group-exited { - opacity: 0; - display: none; - } + &.Group-exited { + opacity: 0; + display: none; } &.Group-measuring { @@ -34,22 +45,6 @@ $bulk-actions-button-stacking-order: ( } } -.Group-entering, -.Group-exiting { - opacity: 0; - display: flex; -} - -.Group-entered { - opacity: 1; - display: flex; -} - -.Group-exited { - opacity: 0; - display: none; -} - .ButtonGroupWrapper { width: 100%; max-width: 100%; diff --git a/polaris-react/src/components/BulkActions/BulkActions.tsx b/polaris-react/src/components/BulkActions/BulkActions.tsx index 049c447c6d2..abae9cc8dce 100644 --- a/polaris-react/src/components/BulkActions/BulkActions.tsx +++ b/polaris-react/src/components/BulkActions/BulkActions.tsx @@ -1,5 +1,5 @@ import React, {PureComponent, createRef} from 'react'; -import {Transition} from 'react-transition-group'; +import {TransitionGroup, CSSTransition} from 'react-transition-group'; import {debounce} from '../../utilities/debounce'; import {classNames} from '../../utilities/css'; @@ -41,6 +41,8 @@ export interface BulkActionsProps { onSelectModeToggle?(selectMode: boolean): void; /** Callback when more actions button is toggled */ onMoreActionPopoverToggle?(isOpen: boolean): void; + /** If the BulkActions is currently sticky in view */ + isSticky?: boolean; } type CombinedProps = BulkActionsProps & { @@ -188,7 +190,7 @@ class BulkActionsInner extends PureComponent { // eslint-disable-next-line @typescript-eslint/member-ordering render() { - const {selectMode, disabled, promotedActions, i18n} = this.props; + const {selectMode, disabled, promotedActions, i18n, isSticky} = this.props; const actionSections = this.actionSections(); @@ -294,31 +296,34 @@ class BulkActionsInner extends PureComponent { } const group = ( - - {(status: TransitionStatus) => { - const groupClassName = classNames( - styles.Group, - !measuring && styles[`Group-${status}`], - measuring && styles['Group-measuring'], - ); - return ( -
    - -
    - {groupContent} + + + {(status: TransitionStatus) => { + const groupClassName = classNames( + styles.Group, + !isSticky && styles['Group-not-sticky'], + !measuring && isSticky && styles[`Group-${status}`], + measuring && styles['Group-measuring'], + ); + return ( +
    + +
    + {groupContent} +
    -
    - ); - }} - + ); + }} + + ); return
    {group}
    ; diff --git a/polaris-react/src/components/IndexTable/IndexTable.tsx b/polaris-react/src/components/IndexTable/IndexTable.tsx index 02b0818630f..904d5866fbd 100644 --- a/polaris-react/src/components/IndexTable/IndexTable.tsx +++ b/polaris-react/src/components/IndexTable/IndexTable.tsx @@ -563,6 +563,7 @@ function IndexTableBase({ promotedActions={promotedActions} actions={actions} onSelectModeToggle={condensed ? handleSelectModeToggle : undefined} + isSticky={isBulkActionsSticky} />
    ) : null; From 7b45cb78f7c382f0506e4c9331e213f7680f2ddd Mon Sep 17 00:00:00 2001 From: Marc Thomas Date: Fri, 7 Oct 2022 19:31:01 +0100 Subject: [PATCH 09/32] chore: enable correct sizing with asymmetric layouts --- .../components/BulkActions/BulkActions.scss | 3 +- .../components/BulkActions/BulkActions.tsx | 63 ++++++++++--------- .../tests/use-is-bulk-actions-sticky.test.tsx | 40 ++++++++++-- .../hooks/use-is-bulk-actions-sticky.ts | 31 +++++++-- .../src/components/IndexTable/IndexTable.tsx | 5 ++ .../components/ResourceList/ResourceList.scss | 1 - .../components/ResourceList/ResourceList.tsx | 6 ++ 7 files changed, 106 insertions(+), 43 deletions(-) diff --git a/polaris-react/src/components/BulkActions/BulkActions.scss b/polaris-react/src/components/BulkActions/BulkActions.scss index d06199e445d..47919f3b77c 100644 --- a/polaris-react/src/components/BulkActions/BulkActions.scss +++ b/polaris-react/src/components/BulkActions/BulkActions.scss @@ -11,7 +11,8 @@ $bulk-actions-button-stacking-order: ( align-items: center; flex-wrap: wrap; opacity: 0; - width: 90vw; + // width: 90vw; + width: 100%; justify-content: center; transition: var(--p-duration-250) var(--p-ease-in); transform: translateY(120px); diff --git a/polaris-react/src/components/BulkActions/BulkActions.tsx b/polaris-react/src/components/BulkActions/BulkActions.tsx index abae9cc8dce..74de0b519c3 100644 --- a/polaris-react/src/components/BulkActions/BulkActions.tsx +++ b/polaris-react/src/components/BulkActions/BulkActions.tsx @@ -1,5 +1,5 @@ import React, {PureComponent, createRef} from 'react'; -import {TransitionGroup, CSSTransition} from 'react-transition-group'; +import {Transition} from 'react-transition-group'; import {debounce} from '../../utilities/debounce'; import {classNames} from '../../utilities/css'; @@ -43,6 +43,8 @@ export interface BulkActionsProps { onMoreActionPopoverToggle?(isOpen: boolean): void; /** If the BulkActions is currently sticky in view */ isSticky?: boolean; + /** The width of the BulkActions */ + width: number; } type CombinedProps = BulkActionsProps & { @@ -190,7 +192,8 @@ class BulkActionsInner extends PureComponent { // eslint-disable-next-line @typescript-eslint/member-ordering render() { - const {selectMode, disabled, promotedActions, i18n, isSticky} = this.props; + const {selectMode, disabled, promotedActions, i18n, isSticky, width} = + this.props; const actionSections = this.actionSections(); @@ -296,34 +299,36 @@ class BulkActionsInner extends PureComponent { } const group = ( - - - {(status: TransitionStatus) => { - const groupClassName = classNames( - styles.Group, - !isSticky && styles['Group-not-sticky'], - !measuring && isSticky && styles[`Group-${status}`], - measuring && styles['Group-measuring'], - ); - return ( -
    - -
    - {groupContent} -
    + + {(status: TransitionStatus) => { + const groupClassName = classNames( + styles.Group, + !isSticky && styles['Group-not-sticky'], + !measuring && isSticky && styles[`Group-${status}`], + measuring && styles['Group-measuring'], + ); + return ( +
    + +
    + {groupContent}
    - ); - }} - - +
    + ); + }} +
    ); return
    {group}
    ; diff --git a/polaris-react/src/components/BulkActions/hooks/tests/use-is-bulk-actions-sticky.test.tsx b/polaris-react/src/components/BulkActions/hooks/tests/use-is-bulk-actions-sticky.test.tsx index 52cb3f4ddcc..bffe21616ee 100644 --- a/polaris-react/src/components/BulkActions/hooks/tests/use-is-bulk-actions-sticky.test.tsx +++ b/polaris-react/src/components/BulkActions/hooks/tests/use-is-bulk-actions-sticky.test.tsx @@ -14,12 +14,16 @@ function Component({selectMode}: ComponentProps) { tableMeasurerRef, isBulkActionsSticky, bulkActionsAbsoluteOffset, + bulkActionsMaxWidth, + bulkActionsOffsetLeft, } = useIsBulkActionsSticky(selectMode); return (

    {isBulkActionsSticky ? 'true' : 'false'}

    {bulkActionsAbsoluteOffset} + {bulkActionsMaxWidth} + {bulkActionsOffsetLeft}
    @@ -34,7 +38,11 @@ describe('useIsBulkActionsSticky', () => { Element.prototype, 'getBoundingClientRect', ); - setGetBoundingClientRect(400); + setGetBoundingClientRect({ + width: 600, + height: 400, + left: 20, + }); intersectionObserver.mock(); }); @@ -47,15 +55,27 @@ describe('useIsBulkActionsSticky', () => { describe('when measuring', () => { it('returns the offset correctly when select mode is false', () => { const component = mountWithApp(); - const result = component.find('span')?.text(); + const result = component.findAll('span')[0]?.text(); expect(result).toBe('400'); }); it('returns the offset correctly when select mode is true', () => { const component = mountWithApp(); - const result = component.find('span')?.text(); + const result = component.findAll('span')[0]?.text(); expect(result).toBe('300'); }); + + it('returns the width value correctly', () => { + const component = mountWithApp(); + const result = component.findAll('span')[1]?.text(); + expect(result).toBe('600'); + }); + + it('returns the left value correctly', () => { + const component = mountWithApp(); + const result = component.findAll('span')[2]?.text(); + expect(result).toBe('20'); + }); }); describe('when isIntersecting', () => { @@ -94,13 +114,21 @@ describe('useIsBulkActionsSticky', () => { }); }); - function setGetBoundingClientRect(height: number) { + function setGetBoundingClientRect({ + width, + height, + left, + }: { + width: number; + height: number; + left: number; + }) { getBoundingClientRectSpy.mockImplementation(() => { return { height, - width: 0, + width, top: 0, - left: 0, + left, bottom: 0, right: 0, x: 0, diff --git a/polaris-react/src/components/BulkActions/hooks/use-is-bulk-actions-sticky.ts b/polaris-react/src/components/BulkActions/hooks/use-is-bulk-actions-sticky.ts index bf5e40a2c73..38bc274cd67 100644 --- a/polaris-react/src/components/BulkActions/hooks/use-is-bulk-actions-sticky.ts +++ b/polaris-react/src/components/BulkActions/hooks/use-is-bulk-actions-sticky.ts @@ -9,29 +9,46 @@ const PADDING_IN_SELECT_MODE = 100; export function useIsBulkActionsSticky(selectMode: boolean) { const [isBulkActionsSticky, setIsSticky] = useState(false); const [bulkActionsAbsoluteOffset, setBulkActionsAbsoluteOffset] = useState(0); + const [bulkActionsMaxWidth, setBulkActionsMaxWidth] = useState(0); + const [bulkActionsOffsetLeft, setBulkActionsOffsetLeft] = useState(0); const bulkActionsIntersectionRef = useRef(null); const tableMeasurerRef = useRef(null); useEffect(() => { - function computeTableHeight() { + function computeTableDimensions() { const node = tableMeasurerRef.current; if (!node) { - return 0; + return { + maxWidth: 0, + offsetHeight: 0, + offsetLeft: 0, + }; } + const box = node.getBoundingClientRect(); const paddingHeight = selectMode ? PADDING_IN_SELECT_MODE : 0; - return node.getBoundingClientRect().height - paddingHeight; + const offsetHeight = box.height - paddingHeight; + const maxWidth = box.width; + const offsetLeft = box.left; + + return { + offsetHeight, + offsetLeft, + maxWidth, + }; } - const tableHeight = computeTableHeight(); + const {offsetHeight, offsetLeft, maxWidth} = computeTableDimensions(); const debouncedComputeTableHeight = debounce( - computeTableHeight, + computeTableDimensions, DEBOUNCE_PERIOD, { trailing: true, }, ); - setBulkActionsAbsoluteOffset(tableHeight); + setBulkActionsAbsoluteOffset(offsetHeight); + setBulkActionsMaxWidth(maxWidth); + setBulkActionsOffsetLeft(offsetLeft); window.addEventListener('resize', debouncedComputeTableHeight); @@ -73,5 +90,7 @@ export function useIsBulkActionsSticky(selectMode: boolean) { tableMeasurerRef, isBulkActionsSticky, bulkActionsAbsoluteOffset, + bulkActionsMaxWidth, + bulkActionsOffsetLeft, }; } diff --git a/polaris-react/src/components/IndexTable/IndexTable.tsx b/polaris-react/src/components/IndexTable/IndexTable.tsx index 904d5866fbd..13359fbf29b 100644 --- a/polaris-react/src/components/IndexTable/IndexTable.tsx +++ b/polaris-react/src/components/IndexTable/IndexTable.tsx @@ -170,6 +170,8 @@ function IndexTableBase({ tableMeasurerRef, isBulkActionsSticky, bulkActionsAbsoluteOffset, + bulkActionsMaxWidth, + bulkActionsOffsetLeft, } = useIsBulkActionsSticky(selectMode); const tableBodyRef = useCallback( @@ -554,6 +556,8 @@ function IndexTableBase({ data-condensed={condensed} style={{ top: isBulkActionsSticky ? undefined : bulkActionsAbsoluteOffset, + width: bulkActionsMaxWidth, + left: isBulkActionsSticky ? bulkActionsOffsetLeft : undefined, }} > {loadingMarkup} @@ -564,6 +568,7 @@ function IndexTableBase({ actions={actions} onSelectModeToggle={condensed ? handleSelectModeToggle : undefined} isSticky={isBulkActionsSticky} + width={bulkActionsMaxWidth} />
    ) : null; diff --git a/polaris-react/src/components/ResourceList/ResourceList.scss b/polaris-react/src/components/ResourceList/ResourceList.scss index 33d52d97c29..b1c7e05731f 100644 --- a/polaris-react/src/components/ResourceList/ResourceList.scss +++ b/polaris-react/src/components/ResourceList/ResourceList.scss @@ -32,7 +32,6 @@ $breakpoints-empty-search-results-height-up: '(min-height: #{breakpoint(600px)}) position: relative; background-color: var(--p-surface); z-index: resource-list(header-outer-wrapper-stacking-order); - overflow: hidden; border-top-left-radius: var(--p-border-radius-2); border-top-right-radius: var(--p-border-radius-2); diff --git a/polaris-react/src/components/ResourceList/ResourceList.tsx b/polaris-react/src/components/ResourceList/ResourceList.tsx index 06d4b5dfb7a..8bc0e74c197 100644 --- a/polaris-react/src/components/ResourceList/ResourceList.tsx +++ b/polaris-react/src/components/ResourceList/ResourceList.tsx @@ -171,6 +171,8 @@ export const ResourceList: ResourceListType = function ResourceList({ tableMeasurerRef, isBulkActionsSticky, bulkActionsAbsoluteOffset, + bulkActionsMaxWidth, + bulkActionsOffsetLeft, } = useIsBulkActionsSticky(selectMode); const defaultResourceName = useLazyRef(() => ({ @@ -572,6 +574,8 @@ export const ResourceList: ResourceListType = function ResourceList({ className={bulkActionClassNames} style={{ top: isBulkActionsSticky ? undefined : bulkActionsAbsoluteOffset, + width: bulkActionsMaxWidth, + left: isBulkActionsSticky ? bulkActionsOffsetLeft : undefined, }} > ({ promotedActions={promotedBulkActions} actions={bulkActions} disabled={loading} + isSticky={isBulkActionsSticky} + width={bulkActionsMaxWidth} />
    ) : null; From af6de8ba4da0b97a06ad911346687942e3c95a01 Mon Sep 17 00:00:00 2001 From: Marc Thomas Date: Fri, 7 Oct 2022 19:34:47 +0100 Subject: [PATCH 10/32] fix test --- .../BulkActions/tests/BulkActions.test.tsx | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/polaris-react/src/components/BulkActions/tests/BulkActions.test.tsx b/polaris-react/src/components/BulkActions/tests/BulkActions.test.tsx index d63465fde21..86c26745b29 100644 --- a/polaris-react/src/components/BulkActions/tests/BulkActions.test.tsx +++ b/polaris-react/src/components/BulkActions/tests/BulkActions.test.tsx @@ -15,6 +15,8 @@ interface Props { bulkActions: BulkActionButtonProps['content'][]; promotedActions: NonNullable; disabled: boolean; + width: number; + isSticky: boolean; } const bulkActionProps: Props = { @@ -28,6 +30,8 @@ const bulkActionProps: Props = { }, ], disabled: false, + width: 500, + isSticky: false, }; describe('', () => { @@ -177,6 +181,8 @@ describe('', () => { }, ], disabled: false, + width: 500, + isSticky: false, }; const bulkActions = mountWithApp(); @@ -217,6 +223,8 @@ describe('', () => { }, ], disabled: false, + width: 500, + isSticky: false, }; const bulkActions = mountWithApp(); const bulkActionButtons = bulkActions.findAll(BulkActionButton); @@ -246,6 +254,8 @@ describe('', () => { }, ], disabled: false, + width: 500, + isSticky: false, }; const bulkActions = mountWithApp(); @@ -269,6 +279,8 @@ describe('', () => { }, ], disabled: false, + width: 500, + isSticky: false, }; const bulkActions = mountWithApp(); From fa2d63f47733d99cc20b7f8b395967b505788b37 Mon Sep 17 00:00:00 2001 From: Marc Thomas Date: Wed, 12 Oct 2022 12:25:44 +0100 Subject: [PATCH 11/32] chore: fix spacing --- .../src/components/CheckableButton/CheckableButton.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/polaris-react/src/components/CheckableButton/CheckableButton.scss b/polaris-react/src/components/CheckableButton/CheckableButton.scss index f48ec71bb43..ae59ac0c9e4 100644 --- a/polaris-react/src/components/CheckableButton/CheckableButton.scss +++ b/polaris-react/src/components/CheckableButton/CheckableButton.scss @@ -68,6 +68,7 @@ $button-vertical-padding: calc( box-shadow: none; background: transparent; border: none; + padding-right: var(--p-space-1); &:hover { background: transparent; From 11e9c01a0010e7713602da1b75f60c2f82852a21 Mon Sep 17 00:00:00 2001 From: Zakaria Warsame Date: Wed, 19 Oct 2022 12:40:50 -0400 Subject: [PATCH 12/32] make the popover alignment right --- polaris-react/src/components/BulkActions/BulkActions.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/polaris-react/src/components/BulkActions/BulkActions.tsx b/polaris-react/src/components/BulkActions/BulkActions.tsx index 74de0b519c3..d929579745d 100644 --- a/polaris-react/src/components/BulkActions/BulkActions.tsx +++ b/polaris-react/src/components/BulkActions/BulkActions.tsx @@ -276,6 +276,7 @@ class BulkActionsInner extends PureComponent { indicator={this.isNewBadgeInBadgeActions()} /> } + preferredAlignment="right" onClose={this.togglePopover} > Date: Wed, 19 Oct 2022 15:40:11 -0400 Subject: [PATCH 13/32] remove comments --- polaris-react/src/components/BulkActions/BulkActions.scss | 1 - polaris-react/src/components/IndexTable/IndexTable.scss | 1 - 2 files changed, 2 deletions(-) diff --git a/polaris-react/src/components/BulkActions/BulkActions.scss b/polaris-react/src/components/BulkActions/BulkActions.scss index 47919f3b77c..bab621da95b 100644 --- a/polaris-react/src/components/BulkActions/BulkActions.scss +++ b/polaris-react/src/components/BulkActions/BulkActions.scss @@ -11,7 +11,6 @@ $bulk-actions-button-stacking-order: ( align-items: center; flex-wrap: wrap; opacity: 0; - // width: 90vw; width: 100%; justify-content: center; transition: var(--p-duration-250) var(--p-ease-in); diff --git a/polaris-react/src/components/IndexTable/IndexTable.scss b/polaris-react/src/components/IndexTable/IndexTable.scss index 3531659ecbb..db6b6f2eb7c 100644 --- a/polaris-react/src/components/IndexTable/IndexTable.scss +++ b/polaris-react/src/components/IndexTable/IndexTable.scss @@ -9,7 +9,6 @@ --pc-index-table-bulk-actions: 36; --pc-index-table-loading-panel: 37; position: relative; - // overflow: hidden; border-radius: inherit; } From 13477183236559cb3c6183cd4669544d0d19f917 Mon Sep 17 00:00:00 2001 From: Zakaria Warsame Date: Tue, 25 Oct 2022 18:20:05 -0400 Subject: [PATCH 14/32] test the SelectAllActions component instead of BulkActions --- .../components/IndexTable/tests/IndexTable.test.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/polaris-react/src/components/IndexTable/tests/IndexTable.test.tsx b/polaris-react/src/components/IndexTable/tests/IndexTable.test.tsx index a3e6ed55ba1..70d2359ba55 100644 --- a/polaris-react/src/components/IndexTable/tests/IndexTable.test.tsx +++ b/polaris-react/src/components/IndexTable/tests/IndexTable.test.tsx @@ -489,9 +489,9 @@ describe('', () => { , ); - indexTable.find(BulkActions)!.trigger('onToggleAll'); + indexTable.find(SelectAllActions)!.trigger('onToggleAll'); - expect(indexTable).toContainReactComponent(BulkActions, { + expect(indexTable).toContainReactComponent(SelectAllActions, { smallScreen: expect.any(Boolean), }); }); @@ -515,9 +515,9 @@ describe('', () => { , ); - indexTable.find(BulkActions)!.trigger('onToggleAll'); + indexTable.find(SelectAllActions)!.trigger('onToggleAll'); - expect(indexTable).toContainReactComponent(BulkActions, { + expect(indexTable).toContainReactComponent(SelectAllActions, { smallScreen: false, }); @@ -528,7 +528,7 @@ describe('', () => { window.dispatchEvent(new Event('resize')); }); - expect(indexTable).toContainReactComponent(BulkActions, { + expect(indexTable).toContainReactComponent(SelectAllActions, { smallScreen: true, }); }); From 234ef143dd8d86ab43f5ce5e30d5728b0d664ab4 Mon Sep 17 00:00:00 2001 From: Zakaria Warsame Date: Wed, 26 Oct 2022 15:04:11 -0400 Subject: [PATCH 15/32] only render bulkactions in selectmode --- .../ResourceList/ResourceList.stories.tsx | 1 + .../components/ResourceList/ResourceList.tsx | 41 ++++++++++--------- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/polaris-react/src/components/ResourceList/ResourceList.stories.tsx b/polaris-react/src/components/ResourceList/ResourceList.stories.tsx index 7589242a30c..94a9d3ca25d 100644 --- a/polaris-react/src/components/ResourceList/ResourceList.stories.tsx +++ b/polaris-react/src/components/ResourceList/ResourceList.stories.tsx @@ -250,6 +250,7 @@ export function WithBulkActions() { export function WithBulkActionsAndManyItems() { const [selectedItems, setSelectedItems] = useState([]); + console.log(selectedItems); const resourceName = { singular: 'customer', diff --git a/polaris-react/src/components/ResourceList/ResourceList.tsx b/polaris-react/src/components/ResourceList/ResourceList.tsx index 8bc0e74c197..b1df3388bd9 100644 --- a/polaris-react/src/components/ResourceList/ResourceList.tsx +++ b/polaris-react/src/components/ResourceList/ResourceList.tsx @@ -569,26 +569,27 @@ export const ResourceList: ResourceListType = function ResourceList({ isBulkActionsSticky && styles.BulkActionsWrapperSticky, ); - const bulkActionsMarkup = isSelectable ? ( -
    - -
    - ) : null; + const bulkActionsMarkup = + isSelectable && selectMode ? ( +
    + +
    + ) : null; const filterControlMarkup = filterControl ? (
    {filterControl}
    From b531f5b05c2a47b5e08669d7c489d645a7714890 Mon Sep 17 00:00:00 2001 From: Zakaria Warsame Date: Wed, 26 Oct 2022 15:11:45 -0400 Subject: [PATCH 16/32] removes unnecessary code --- .../src/components/ResourceList/ResourceList.stories.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/polaris-react/src/components/ResourceList/ResourceList.stories.tsx b/polaris-react/src/components/ResourceList/ResourceList.stories.tsx index 94a9d3ca25d..7589242a30c 100644 --- a/polaris-react/src/components/ResourceList/ResourceList.stories.tsx +++ b/polaris-react/src/components/ResourceList/ResourceList.stories.tsx @@ -250,7 +250,6 @@ export function WithBulkActions() { export function WithBulkActionsAndManyItems() { const [selectedItems, setSelectedItems] = useState([]); - console.log(selectedItems); const resourceName = { singular: 'customer', From a64188a4cee801d1c1e7821fb88b59dc59fd652f Mon Sep 17 00:00:00 2001 From: Zakaria Warsame Date: Wed, 26 Oct 2022 16:52:36 -0400 Subject: [PATCH 17/32] chore: use correct tests --- .../ResourceList/tests/ResourceList.test.tsx | 32 ++++--------------- 1 file changed, 7 insertions(+), 25 deletions(-) diff --git a/polaris-react/src/components/ResourceList/tests/ResourceList.test.tsx b/polaris-react/src/components/ResourceList/tests/ResourceList.test.tsx index 767bea049f3..a37bbe26b74 100644 --- a/polaris-react/src/components/ResourceList/tests/ResourceList.test.tsx +++ b/polaris-react/src/components/ResourceList/tests/ResourceList.test.tsx @@ -103,7 +103,7 @@ describe('', () => { expect(resourceList).not.toContainReactComponent(SelectAllActions); }); - it('does render bulk actions if the promotedBulkActions prop is provided', () => { + it('does render SelectAllActions if the promotedBulkActions prop is provided', () => { const resourceList = mountWithApp( ', () => { promotedBulkActions={promotedBulkActions} />, ); - expect(resourceList).toContainReactComponent(BulkActions); + expect(resourceList).toContainReactComponent(SelectAllActions); }); it('renders bulk actions if the bulkActions prop is provided', () => { @@ -122,7 +122,7 @@ describe('', () => { bulkActions={bulkActions} />, ); - expect(resourceList).toContainReactComponent(BulkActions); + expect(resourceList).toContainReactComponent(SelectAllActions); }); it('renders a `CheckableButton` if the `selectable` prop is true', () => { @@ -920,11 +920,11 @@ describe('', () => { />, ); - expect(resourceList).toContainReactComponent(BulkActions, { + expect(resourceList).toContainReactComponent(SelectAllActions, { selectMode: false, }); resourceList.setProps({selectedItems: ['1']}); - expect(resourceList).toContainReactComponent(BulkActions, { + expect(resourceList).toContainReactComponent(SelectAllActions, { selectMode: true, }); }); @@ -939,11 +939,11 @@ describe('', () => { />, ); - expect(resourceList).toContainReactComponent(BulkActions, { + expect(resourceList).toContainReactComponent(SelectAllActions, { selectMode: true, }); resourceList.setProps({selectedItems: []}); - expect(resourceList).toContainReactComponent(BulkActions, { + expect(resourceList).toContainReactComponent(SelectAllActions, { selectMode: false, }); }); @@ -1187,24 +1187,6 @@ describe('', () => { labelInline: false, }); }); - - it('select mode is turned off on large screen when no items are selected', () => { - const resourceList = mountWithApp( - , - ); - - resourceList.find(BulkActions)!.trigger('onSelectModeToggle', true); - // eslint-disable-next-line import/no-deprecated - resourceList.find(EventListener)!.trigger('handler'); - expect(resourceList).toContainReactComponent(BulkActions, { - selectMode: false, - }); - }); }); describe('isFiltered', () => { From 168e5e033e54b77b1b0678009a0b0d381aa8bcb9 Mon Sep 17 00:00:00 2001 From: Marc Thomas Date: Fri, 18 Nov 2022 13:44:27 +0000 Subject: [PATCH 18/32] chore: remove code from rebase --- polaris-react/src/components/IndexTable/IndexTable.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/polaris-react/src/components/IndexTable/IndexTable.tsx b/polaris-react/src/components/IndexTable/IndexTable.tsx index 13359fbf29b..be5fc259c9d 100644 --- a/polaris-react/src/components/IndexTable/IndexTable.tsx +++ b/polaris-react/src/components/IndexTable/IndexTable.tsx @@ -16,7 +16,6 @@ import {Stack} from '../Stack'; import {Sticky} from '../Sticky'; import {Spinner} from '../Spinner'; import {Text} from '../Text'; -import {VisuallyHidden} from '../VisuallyHidden'; import {Tooltip} from '../Tooltip'; import {UnstyledButton} from '../UnstyledButton'; import { From 1ded4dd72468b1736015904b50b90932d105614e Mon Sep 17 00:00:00 2001 From: Marc Thomas Date: Fri, 18 Nov 2022 14:44:47 +0000 Subject: [PATCH 19/32] chore: fix offset --- polaris-react/src/components/IndexTable/IndexTable.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polaris-react/src/components/IndexTable/IndexTable.scss b/polaris-react/src/components/IndexTable/IndexTable.scss index db6b6f2eb7c..0e1ac08a624 100644 --- a/polaris-react/src/components/IndexTable/IndexTable.scss +++ b/polaris-react/src/components/IndexTable/IndexTable.scss @@ -2,7 +2,7 @@ .IndexTable { --pc-index-table-translate-offset: 35px; - --pc-index-table-table-header-offset: 35px; + --pc-index-table-table-header-offset: 36px; --pc-index-table-cell: 1; --pc-index-table-sticky-cell: 31; --pc-index-table-scroll-bar: 35; From 78363bca63a1b9a943d7c73d9e104be8d4a6800b Mon Sep 17 00:00:00 2001 From: Marc Thomas Date: Fri, 18 Nov 2022 15:48:54 +0000 Subject: [PATCH 20/32] chore: fix placement of loading --- polaris-react/src/components/IndexTable/IndexTable.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/polaris-react/src/components/IndexTable/IndexTable.tsx b/polaris-react/src/components/IndexTable/IndexTable.tsx index be5fc259c9d..054192f5f5a 100644 --- a/polaris-react/src/components/IndexTable/IndexTable.tsx +++ b/polaris-react/src/components/IndexTable/IndexTable.tsx @@ -559,8 +559,6 @@ function IndexTableBase({ left: isBulkActionsSticky ? bulkActionsOffsetLeft : undefined, }} > - {loadingMarkup} - + {loadingMarkup}
    ) : null; From 2ee5e132a68827f1e73f43171845092418ecdd7e Mon Sep 17 00:00:00 2001 From: Marc Thomas Date: Fri, 18 Nov 2022 16:42:54 +0000 Subject: [PATCH 21/32] chore: tidy up checkable button --- polaris-react/locales/en.json | 4 +- .../CheckableButton/CheckableButton.scss | 85 +++---------------- .../CheckableButton/CheckableButton.tsx | 28 +----- .../src/components/IndexTable/IndexTable.tsx | 82 +++++++++--------- .../components/ResourceList/ResourceList.tsx | 12 +-- .../SelectAllActions/SelectAllActions.tsx | 11 +-- .../src/utilities/resource-list/types.ts | 2 +- 7 files changed, 56 insertions(+), 168 deletions(-) diff --git a/polaris-react/locales/en.json b/polaris-react/locales/en.json index 3ced86e8bc5..4630af4a33c 100644 --- a/polaris-react/locales/en.json +++ b/polaris-react/locales/en.json @@ -162,7 +162,7 @@ "defaultItemSingular": "Item", "defaultItemPlural": "Items", "allItemsSelected": "All {itemsLength}+ {resourceNamePlural} are selected.", - "selected": "{selectedItemsCount} selected", + "selected": "{selectedItemsCount} selected.", "a11yCheckboxDeselectAllSingle": "Deselect {resourceNameSingular}", "a11yCheckboxSelectAllSingle": "Select {resourceNameSingular}", "a11yCheckboxDeselectAllMultiple": "Deselect all {itemsLength} {resourceNamePlural}", @@ -174,7 +174,7 @@ "onboardingBadgeText": "New", "resourceLoadingAccessibilityLabel": "Loading {resourceNamePlural}…", "selectAllLabel": "Select all {resourceNamePlural}", - "selected": "{selectedItemsCount} selected", + "selected": "{selectedItemsCount} selected.", "undo": "Undo", "selectAllItems": "Select all {itemsLength}+ {resourceNamePlural}", "selectItem": "Select {resourceName}", diff --git a/polaris-react/src/components/CheckableButton/CheckableButton.scss b/polaris-react/src/components/CheckableButton/CheckableButton.scss index ae59ac0c9e4..b150a44b5fa 100644 --- a/polaris-react/src/components/CheckableButton/CheckableButton.scss +++ b/polaris-react/src/components/CheckableButton/CheckableButton.scss @@ -7,7 +7,8 @@ $button-vertical-padding: calc( .CheckableButton { @include recolor-icon(var(--p-icon-on-interactive)); - font-size: var(--p-font-size-100); + color: var(--p-text); + font-size: var(--p-font-size-75); font-weight: var(--p-font-weight-medium); line-height: var(--p-font-line-height-1); text-transform: initial; @@ -17,96 +18,32 @@ $button-vertical-padding: calc( min-height: 36px; min-width: 36px; margin: 0; - padding: $button-vertical-padding var(--p-space-4); + padding: $button-vertical-padding var(--p-space-1) $button-vertical-padding + var(--p-space-4); cursor: pointer; user-select: none; text-decoration: none; text-align: left; - border-radius: var(--p-border-radius-1); - width: 100%; - background: var(--p-surface); - box-shadow: var(--p-shadow-button); - border: var(--p-border-width-1) solid var(--p-border-neutral-subdued); - border-top-color: var(--p-border-subdued); - border-bottom-color: var(--p-border-shadow-subdued); - - [data-buttongroup-segmented='true'] & { - border-top-right-radius: 0; - border-bottom-right-radius: 0; - } - - &:hover { - background: var(--p-action-secondary-hovered); - } + border-radius: var(--p-border-radius-base); + width: auto; + &:hover, &:active { - background: var(--p-action-secondary-pressed); - } - - &.CheckableButton-measuring { - font-size: 15px; - font-weight: var(--p-font-weight-bold); - - // simulates measuring with an additional digit (e.g. 00 instead of 0) - &::before { - content: ''; - display: inline-block; - width: 15px; - } - } - - @media #{$p-breakpoints-sm-up} { - flex: 0 1 auto; + background: transparent; } &:focus { outline: none; } - - &.CheckableButton-plain { - border-radius: var(--p-border-radius-base); - box-shadow: none; - background: transparent; - border: none; - padding-right: var(--p-space-1); - - &:hover { - background: transparent; - } - } - - &.CheckableButton-autoWidth { - width: auto; - font-size: var(--p-font-size-75); - - @media #{$p-breakpoints-sm-up} { - flex: none; - } - } - - &.CheckableButton-selectMode { - color: var(--p-text-subdued); - font-weight: var(--p-font-weight-medium); - } - - &.CheckableButton-selected { - color: var(--p-text); - } } .Checkbox { pointer-events: none; height: var(--p-choice-size); width: var(--p-choice-size); - margin-left: calc(-1 * var(--p-space-2) - var(--p-control-border-width)); -} - -.CheckableButton-selectMode { - .Checkbox { - margin-left: calc( - -1 * var(--p-space-2) - var(--p-control-border-width) - var(--p-border-width-1) - ); - } + margin-left: calc( + -1 * var(--p-space-2) - var(--p-control-border-width) - var(--p-border-width-1) + ); } .Label { diff --git a/polaris-react/src/components/CheckableButton/CheckableButton.tsx b/polaris-react/src/components/CheckableButton/CheckableButton.tsx index 310ab1020be..558ebac8153 100644 --- a/polaris-react/src/components/CheckableButton/CheckableButton.tsx +++ b/polaris-react/src/components/CheckableButton/CheckableButton.tsx @@ -14,12 +14,8 @@ export interface CheckableButtonProps { accessibilityLabel?: string; label?: string; selected?: boolean | 'indeterminate'; - selectMode?: boolean; - plain?: boolean; - measuring?: boolean; disabled?: boolean; onToggleAll?(): void; - autoWidth?: boolean; ariaLive?: 'off' | 'assertive' | 'polite'; } @@ -28,22 +24,14 @@ export function CheckableButton({ label = '', onToggleAll, selected, - selectMode, - plain, - measuring, disabled, - autoWidth, ariaLive, }: CheckableButtonProps) { const checkBoxRef = useRef(null); const {registerCheckableButtons} = useContext(ResourceListContext); - let currentKey: CheckableButtonKey = 'plain'; - - if (autoWidth) { - currentKey = 'selectAll'; - } + const currentKey: CheckableButtonKey = 'plain'; useEffect(() => { if (checkBoxRef.current && registerCheckableButtons) { @@ -51,19 +39,7 @@ export function CheckableButton({ } }, [currentKey, registerCheckableButtons]); - const className = plain - ? classNames( - styles.CheckableButton, - styles['CheckableButton-plain'], - autoWidth && styles['CheckableButton-autoWidth'], - ) - : classNames( - styles.CheckableButton, - selectMode && styles['CheckableButton-selectMode'], - selected && styles['CheckableButton-selected'], - measuring && styles['CheckableButton-measuring'], - autoWidth && styles['CheckableButton-autoWidth'], - ); + const className = classNames(styles.CheckableButton); return (
    diff --git a/polaris-react/src/components/IndexTable/IndexTable.tsx b/polaris-react/src/components/IndexTable/IndexTable.tsx index 054192f5f5a..c54e34a3df2 100644 --- a/polaris-react/src/components/IndexTable/IndexTable.tsx +++ b/polaris-react/src/components/IndexTable/IndexTable.tsx @@ -153,7 +153,6 @@ function IndexTableBase({ const [stickyWrapper, setStickyWrapper] = useState(null); const [hideScrollContainer, setHideScrollContainer] = useState(false); - const [smallScreen, setSmallScreen] = useState(isBreakpointsXS()); const tableHeadings = useRef([]); const stickyTableHeadings = useRef([]); @@ -301,10 +300,6 @@ function IndexTableBase({ handleCanScrollRight(); }, [handleCanScrollRight]); - const handleIsSmallScreen = useCallback(() => { - setSmallScreen(isBreakpointsXS()); - }, []); - const [canFitStickyColumn, setCanFitStickyColumn] = useState(true); const handleCanFitStickyColumn = useCallback(() => { @@ -355,13 +350,11 @@ function IndexTableBase({ resizeTableHeadings(); debounceResizeTableScrollbar(); handleCanScrollRight(); - handleIsSmallScreen(); handleCanFitStickyColumn(); }, [ resizeTableHeadings, debounceResizeTableScrollbar, handleCanScrollRight, - handleIsSmallScreen, handleCanFitStickyColumn, ]); @@ -549,26 +542,27 @@ function IndexTableBase({ const promotedActions = shouldShowActions ? promotedBulkActions : []; const actions = shouldShowActions ? bulkActions : []; - const bulkActionsMarkup = shouldShowBulkActions ? ( -
    - -
    - ) : null; + const bulkActionsMarkup = + shouldShowBulkActions && !condensed ? ( +
    + +
    + ) : null; const stickyHeaderMarkup = (
    @@ -585,23 +579,23 @@ function IndexTableBase({ isSticky && styles['StickyTableHeader-isSticky'], ); - const selectAllActionsMarkup = shouldShowBulkActions ? ( -
    - - {loadingMarkup} -
    - ) : null; + const selectAllActionsMarkup = + shouldShowBulkActions && !condensed ? ( +
    + + {loadingMarkup} +
    + ) : null; const stickyColumnHeaderClassNames = classNames( styles.StickyTableColumnHeader, diff --git a/polaris-react/src/components/ResourceList/ResourceList.tsx b/polaris-react/src/components/ResourceList/ResourceList.tsx index b1df3388bd9..cf4937816b5 100644 --- a/polaris-react/src/components/ResourceList/ResourceList.tsx +++ b/polaris-react/src/components/ResourceList/ResourceList.tsx @@ -528,15 +528,7 @@ export const ResourceList: ResourceListType = function ResourceList({ handleSelectMode(true); } - let checkbox: CheckboxHandles | undefined; - - if (isBreakpointsXS()) { - checkbox = checkableButtons.get('selectAll'); - } else if (newlySelectedItems.length === 0) { - checkbox = checkableButtons.get('plain'); - } else { - checkbox = checkableButtons.get('selectAll'); - } + const checkbox: CheckboxHandles | undefined = checkableButtons.get('plain'); if (onSelectionChange) { onSelectionChange(newlySelectedItems); @@ -559,7 +551,6 @@ export const ResourceList: ResourceListType = function ResourceList({ paginatedSelectAllAction={paginatedSelectAllAction()} paginatedSelectAllText={paginatedSelectAllText()} disabled={loading} - smallScreen={smallScreen} />
    ) : null; @@ -637,7 +628,6 @@ export const ResourceList: ResourceListType = function ResourceList({ accessibilityLabel={selectAllActionsAccessibilityLabel()} label={headerTitle()} onToggleAll={handleToggleAll} - plain disabled={loading} />
    diff --git a/polaris-react/src/components/SelectAllActions/SelectAllActions.tsx b/polaris-react/src/components/SelectAllActions/SelectAllActions.tsx index fc36d05b2e6..3fd5c3b1178 100644 --- a/polaris-react/src/components/SelectAllActions/SelectAllActions.tsx +++ b/polaris-react/src/components/SelectAllActions/SelectAllActions.tsx @@ -14,8 +14,6 @@ type AriaLive = 'off' | 'assertive' | 'polite' | undefined; export interface SelectAllActionsProps { /** Visually hidden text for screen readers */ accessibilityLabel?: string; - /** Whether to render the small screen BulkActions or not */ - smallScreen?: boolean; /** Label for the bulk actions */ label?: string; /** State of the bulk actions checkbox */ @@ -34,7 +32,6 @@ export interface SelectAllActionsProps { export function SelectAllActions({ accessibilityLabel, - smallScreen, label, selected, selectMode, @@ -68,10 +65,8 @@ export function SelectAllActions({ accessibilityLabel, label: hasTextAndAction ? paginatedSelectAllText : label, selected, - selectMode, onToggleAll, disabled, - autoWidth: true, ariaLive, }; const markup = ( @@ -83,11 +78,7 @@ export function SelectAllActions({ ); return (
    - {smallScreen ? ( - - ) : ( - - )} + {paginatedSelectAllMarkup}
    ); diff --git a/polaris-react/src/utilities/resource-list/types.ts b/polaris-react/src/utilities/resource-list/types.ts index 21c64f61205..5bf46d9aee0 100644 --- a/polaris-react/src/utilities/resource-list/types.ts +++ b/polaris-react/src/utilities/resource-list/types.ts @@ -1,7 +1,7 @@ import type {CheckboxHandles} from '../../types'; export type ResourceListSelectedItems = string[] | 'All'; -export type CheckableButtonKey = 'plain' | 'selectAll'; +export type CheckableButtonKey = 'plain'; export type CheckableButtons = Map; export const SELECT_ALL_ITEMS = 'All'; From 84b507e5d62166112d769ab94840eb883b0b64aa Mon Sep 17 00:00:00 2001 From: Marc Thomas Date: Fri, 18 Nov 2022 16:48:37 +0000 Subject: [PATCH 22/32] chore: fix storybook --- .../src/components/IndexTable/IndexTable.stories.tsx | 4 +++- .../src/components/ResourceList/ResourceList.stories.tsx | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/polaris-react/src/components/IndexTable/IndexTable.stories.tsx b/polaris-react/src/components/IndexTable/IndexTable.stories.tsx index 290b6f8a1c8..2776c5067e9 100644 --- a/polaris-react/src/components/IndexTable/IndexTable.stories.tsx +++ b/polaris-react/src/components/IndexTable/IndexTable.stories.tsx @@ -266,7 +266,9 @@ export function SmallScreenLoading() { >

    - {name} + + {name} +

    {location}

    {orders}

    diff --git a/polaris-react/src/components/ResourceList/ResourceList.stories.tsx b/polaris-react/src/components/ResourceList/ResourceList.stories.tsx index 7589242a30c..679f461f211 100644 --- a/polaris-react/src/components/ResourceList/ResourceList.stories.tsx +++ b/polaris-react/src/components/ResourceList/ResourceList.stories.tsx @@ -315,7 +315,9 @@ export function WithBulkActionsAndManyItems() { accessibilityLabel={`View details for ${name}`} >

    - {name} + + {name} +

    {location}
    From 3f39efc1b44248efba18ce432d5bc2520e7ee82e Mon Sep 17 00:00:00 2001 From: Marc Thomas Date: Fri, 18 Nov 2022 16:53:20 +0000 Subject: [PATCH 23/32] chore: update tests --- .../IndexTable/tests/IndexTable.test.tsx | 59 ------------------- .../ResourceList/tests/ResourceList.test.tsx | 6 +- .../tests/SelectAllActions.test.tsx | 10 ---- 3 files changed, 2 insertions(+), 73 deletions(-) diff --git a/polaris-react/src/components/IndexTable/tests/IndexTable.test.tsx b/polaris-react/src/components/IndexTable/tests/IndexTable.test.tsx index 70d2359ba55..845d8649586 100644 --- a/polaris-react/src/components/IndexTable/tests/IndexTable.test.tsx +++ b/polaris-react/src/components/IndexTable/tests/IndexTable.test.tsx @@ -473,65 +473,6 @@ describe('', () => { true, ); }); - - it('passes smallScreen to bulk actions', () => { - const promotedActions = [{content: 'PromotedAction'}]; - - const indexTable = mountWithApp( - - {mockTableItems.map(mockRenderCondensedRow)} - , - ); - - indexTable.find(SelectAllActions)!.trigger('onToggleAll'); - - expect(indexTable).toContainReactComponent(SelectAllActions, { - smallScreen: expect.any(Boolean), - }); - }); - - it('passes an updated smallScreen value to bulk actions after resize', () => { - Object.defineProperty(window, 'innerWidth', { - value: 1000, - }); - - const promotedActions = [{content: 'PromotedAction'}]; - - const indexTable = mountWithApp( - - {mockTableItems.map(mockRenderCondensedRow)} - , - ); - - indexTable.find(SelectAllActions)!.trigger('onToggleAll'); - - expect(indexTable).toContainReactComponent(SelectAllActions, { - smallScreen: false, - }); - - indexTable.act(() => { - Object.defineProperty(window, 'innerWidth', { - value: 300, - }); - window.dispatchEvent(new Event('resize')); - }); - - expect(indexTable).toContainReactComponent(SelectAllActions, { - smallScreen: true, - }); - }); }); describe('condensed', () => { diff --git a/polaris-react/src/components/ResourceList/tests/ResourceList.test.tsx b/polaris-react/src/components/ResourceList/tests/ResourceList.test.tsx index a37bbe26b74..fb240259e50 100644 --- a/polaris-react/src/components/ResourceList/tests/ResourceList.test.tsx +++ b/polaris-react/src/components/ResourceList/tests/ResourceList.test.tsx @@ -971,9 +971,7 @@ describe('', () => { />, ); - resourceList - .find(CheckableButton, {plain: true})! - .trigger('onToggleAll'); + resourceList.find(CheckableButton)!.trigger('onToggleAll'); const deselectAllCheckbox = resourceList .find(SelectAllActions)! @@ -999,7 +997,7 @@ describe('', () => { .trigger('onToggleAll'); const selectAllCheckableCheckbox = resourceList - .findAll(CheckableButton, {plain: true})[0]! + .findAll(CheckableButton)[1]! .find('input', {type: 'checkbox'})!; expect(document.activeElement).toBe( diff --git a/polaris-react/src/components/SelectAllActions/tests/SelectAllActions.test.tsx b/polaris-react/src/components/SelectAllActions/tests/SelectAllActions.test.tsx index d59b19f14d5..9afa5713de1 100644 --- a/polaris-react/src/components/SelectAllActions/tests/SelectAllActions.test.tsx +++ b/polaris-react/src/components/SelectAllActions/tests/SelectAllActions.test.tsx @@ -154,16 +154,6 @@ describe('', () => { expect(cssTransitionComponent).toHaveReactProps({in: true}); }); }); - - it('is passed down to CheckableButton', () => { - const selectAllActions = mountWithApp( - , - ); - const checkableButton = selectAllActions.findAll(CheckableButton); - checkableButton.forEach((checkableButtonComponent) => { - expect(checkableButtonComponent).toHaveReactProps({selectMode: true}); - }); - }); }); describe('disabled', () => { From ca5a4f80a875792a246e82bb57eedbfdd2ca05b3 Mon Sep 17 00:00:00 2001 From: Marc Thomas Date: Mon, 21 Nov 2022 10:12:51 +0000 Subject: [PATCH 24/32] chore: call on resize --- .../hooks/use-is-bulk-actions-sticky.ts | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/polaris-react/src/components/BulkActions/hooks/use-is-bulk-actions-sticky.ts b/polaris-react/src/components/BulkActions/hooks/use-is-bulk-actions-sticky.ts index 38bc274cd67..7a0eb690927 100644 --- a/polaris-react/src/components/BulkActions/hooks/use-is-bulk-actions-sticky.ts +++ b/polaris-react/src/components/BulkActions/hooks/use-is-bulk-actions-sticky.ts @@ -30,13 +30,12 @@ export function useIsBulkActionsSticky(selectMode: boolean) { const maxWidth = box.width; const offsetLeft = box.left; - return { - offsetHeight, - offsetLeft, - maxWidth, - }; + setBulkActionsAbsoluteOffset(offsetHeight); + setBulkActionsMaxWidth(maxWidth); + setBulkActionsOffsetLeft(offsetLeft); } - const {offsetHeight, offsetLeft, maxWidth} = computeTableDimensions(); + + computeTableDimensions(); const debouncedComputeTableHeight = debounce( computeTableDimensions, @@ -46,10 +45,6 @@ export function useIsBulkActionsSticky(selectMode: boolean) { }, ); - setBulkActionsAbsoluteOffset(offsetHeight); - setBulkActionsMaxWidth(maxWidth); - setBulkActionsOffsetLeft(offsetLeft); - window.addEventListener('resize', debouncedComputeTableHeight); return () => From 8c484d11b5d235ad2258f8d63b7115284ba9dc0a Mon Sep 17 00:00:00 2001 From: Marc Thomas Date: Mon, 21 Nov 2022 11:31:25 +0000 Subject: [PATCH 25/32] chore: bump size limt --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1ce4217243c..247de619742 100644 --- a/package.json +++ b/package.json @@ -89,7 +89,7 @@ { "name": "polaris-react-cjs", "path": "polaris-react/build/cjs/index.js", - "limit": "216 kB" + "limit": "218 kB" }, { "name": "polaris-react-esm", From 65f51f9037641dcc249d587b38271449ba127820 Mon Sep 17 00:00:00 2001 From: Marc Thomas Date: Mon, 21 Nov 2022 14:29:24 +0000 Subject: [PATCH 26/32] chore: more accurately represent widths --- .../components/BulkActions/BulkActions.scss | 50 +++---------------- .../components/BulkActions/BulkActions.tsx | 14 ++++-- .../BulkActions/tests/BulkActions.test.tsx | 32 ++++++++++++ 3 files changed, 50 insertions(+), 46 deletions(-) diff --git a/polaris-react/src/components/BulkActions/BulkActions.scss b/polaris-react/src/components/BulkActions/BulkActions.scss index bab621da95b..f366ba9115b 100644 --- a/polaris-react/src/components/BulkActions/BulkActions.scss +++ b/polaris-react/src/components/BulkActions/BulkActions.scss @@ -15,6 +15,7 @@ $bulk-actions-button-stacking-order: ( justify-content: center; transition: var(--p-duration-250) var(--p-ease-in); transform: translateY(120px); + padding: 0 var(--p-space-4); &.Group-not-sticky { transform: none; @@ -46,26 +47,14 @@ $bulk-actions-button-stacking-order: ( } .ButtonGroupWrapper { - width: 100%; + width: auto; + justify-content: flex-start; + padding: var(--p-space-4); + background: var(--p-surface); + border-radius: var(--p-border-radius-2); + box-shadow: var(--p-shadow-popover); max-width: 100%; - // We need the first item of button group on small screen to fill the space - @media #{$p-breakpoints-sm-down} { - // stylelint-disable-next-line, selector-max-combinators, selector-max-type - > div > div:first-child { - flex: 1 1 auto; - } - } - - @media #{$p-breakpoints-sm-up} { - width: auto; - justify-content: flex-start; - padding: var(--p-space-4); - background: var(--p-surface); - border-radius: var(--p-border-radius-2); - box-shadow: var(--p-shadow-popover); - } - .Group-measuring & { position: absolute; width: auto; @@ -76,33 +65,8 @@ $bulk-actions-button-stacking-order: ( white-space: nowrap; } -.CheckableContainer { - flex: 1 1 0; -} - .disabled { @include base-button-disabled; cursor: default; pointer-events: none; } - -.PaginatedSelectAll { - padding: var(--p-space-1) var(--p-space-0); -} - -.Slide { - will-change: transform; - transform: translateY(0); - transition: transform var(--p-ease) var(--p-duration-200); -} - -.Slide-appear, -.Slide-enter, -.Slide-exit { - transform: translateX(calc(-1 * var(--p-space-10))); -} - -.Slide-appearing, -.Slide-entering { - transform: translateY(0); -} diff --git a/polaris-react/src/components/BulkActions/BulkActions.tsx b/polaris-react/src/components/BulkActions/BulkActions.tsx index d929579745d..371b600ec55 100644 --- a/polaris-react/src/components/BulkActions/BulkActions.tsx +++ b/polaris-react/src/components/BulkActions/BulkActions.tsx @@ -28,6 +28,8 @@ type TransitionStatus = 'entering' | 'entered' | 'exiting' | 'exited'; const MAX_PROMOTED_ACTIONS = 2; +const BUTTONS_NODE_ADDITIONAL_WIDTH = 32; + export interface BulkActionsProps { /** List is in a selectable state */ selectMode?: boolean; @@ -101,7 +103,13 @@ class BulkActionsInner extends PureComponent { return 0; } - if (containerWidth >= this.bulkActionsWidth || measuring) { + const containerWidthMinusAdditionalWidth = + containerWidth - BUTTONS_NODE_ADDITIONAL_WIDTH; + + if ( + containerWidthMinusAdditionalWidth >= this.bulkActionsWidth || + measuring + ) { return promotedActions.length; } @@ -115,7 +123,7 @@ class BulkActionsInner extends PureComponent { this.bulkActionsWidth - totalWidth + this.addedMoreActionsWidthForMeasuring; - if (containerWidth >= widthWithRemovedAction) { + if (containerWidthMinusAdditionalWidth >= widthWithRemovedAction) { sufficientSpace = true; } else { counter--; @@ -324,7 +332,7 @@ class BulkActionsInner extends PureComponent { className={styles.ButtonGroupWrapper} ref={this.setButtonsNode} > - {groupContent} +
    {groupContent}
    ); diff --git a/polaris-react/src/components/BulkActions/tests/BulkActions.test.tsx b/polaris-react/src/components/BulkActions/tests/BulkActions.test.tsx index 86c26745b29..d73535207cc 100644 --- a/polaris-react/src/components/BulkActions/tests/BulkActions.test.tsx +++ b/polaris-react/src/components/BulkActions/tests/BulkActions.test.tsx @@ -35,6 +35,22 @@ const bulkActionProps: Props = { }; describe('', () => { + let getBoundingClientRectSpy: jest.SpyInstance; + + beforeEach(() => { + getBoundingClientRectSpy = jest.spyOn( + Element.prototype, + 'getBoundingClientRect', + ); + setGetBoundingClientRect({ + width: 32, + }); + }); + + afterEach(() => { + getBoundingClientRectSpy.mockRestore(); + }); + describe('actions', () => { it('indicator is passed to BulkActionButton when actions contain a new status for badge', () => { const bulkActions = mountWithApp( @@ -336,4 +352,20 @@ describe('', () => { expect(checkableButton).not.toBeNull(); }); }); + + function setGetBoundingClientRect({width}: {width: number}) { + getBoundingClientRectSpy.mockImplementation(() => { + return { + height: 0, + width, + top: 0, + left: 0, + bottom: 0, + right: 0, + x: 0, + y: 0, + toJSON() {}, + }; + }); + } }); From 0f5cffdec7ea09944909aa1f5105e66c87f54f22 Mon Sep 17 00:00:00 2001 From: "translation-platform[bot]" <34770790+translation-platform[bot]@users.noreply.github.com> Date: Tue, 22 Nov 2022 05:15:18 +0000 Subject: [PATCH 27/32] Update 18 translation files --- polaris-react/locales/cs.json | 4 ++-- polaris-react/locales/da.json | 4 ++-- polaris-react/locales/de.json | 4 ++-- polaris-react/locales/es.json | 4 ++-- polaris-react/locales/fi.json | 4 ++-- polaris-react/locales/fr.json | 4 ++-- polaris-react/locales/it.json | 4 ++-- polaris-react/locales/ja.json | 4 ++-- polaris-react/locales/ko.json | 4 ++-- polaris-react/locales/nb.json | 4 ++-- polaris-react/locales/nl.json | 4 ++-- polaris-react/locales/pl.json | 4 ++-- polaris-react/locales/pt-BR.json | 4 ++-- polaris-react/locales/sv.json | 4 ++-- polaris-react/locales/tr.json | 4 ++-- polaris-react/locales/vi.json | 4 ++-- polaris-react/locales/zh-CN.json | 4 ++-- polaris-react/locales/zh-TW.json | 4 ++-- 18 files changed, 36 insertions(+), 36 deletions(-) diff --git a/polaris-react/locales/cs.json b/polaris-react/locales/cs.json index a3a3ed6598a..67554665bed 100644 --- a/polaris-react/locales/cs.json +++ b/polaris-react/locales/cs.json @@ -282,7 +282,7 @@ "defaultItemSingular": "Položka", "defaultItemPlural": "Položky", "allItemsSelected": "Bylo vybráno veškeré zboží typu {resourceNamePlural} ({itemsLength} a více).", - "selected": "Vybráno: {selectedItemsCount}", + "selected": "Vybráno: {selectedItemsCount}.", "a11yCheckboxDeselectAllSingle": "Zrušit výběr: {resourceNameSingular}", "a11yCheckboxSelectAllSingle": "Vybrat: {resourceNameSingular}", "a11yCheckboxDeselectAllMultiple": "Zrušit celý výběr: {resourceNamePlural} ({itemsLength})", @@ -294,7 +294,7 @@ "onboardingBadgeText": "Novinka", "resourceLoadingAccessibilityLabel": "{resourceNamePlural} se načítají…", "selectAllLabel": "Vybrat vše: {resourceNamePlural}", - "selected": "Vybráno: {selectedItemsCount}", + "selected": "Vybráno: {selectedItemsCount}.", "undo": "Vrátit zpět", "selectAllItems": "Vybrat vše typu {resourceNamePlural} ({itemsLength} a více)", "selectItem": "Vybrat: {resourceName}", diff --git a/polaris-react/locales/da.json b/polaris-react/locales/da.json index 86c85e100a7..6f7a60f0173 100644 --- a/polaris-react/locales/da.json +++ b/polaris-react/locales/da.json @@ -280,7 +280,7 @@ "defaultItemSingular": "Vare", "defaultItemPlural": "Varer", "allItemsSelected": "Alle mere end {itemsLength} {resourceNamePlural} er valgt.", - "selected": "{selectedItemsCount} valgt", + "selected": "{selectedItemsCount} valgt.", "a11yCheckboxDeselectAllSingle": "Fravælg {resourceNameSingular}", "a11yCheckboxSelectAllSingle": "Vælg {resourceNameSingular}", "a11yCheckboxDeselectAllMultiple": "Fravælg alle {itemsLength} {resourceNamePlural}", @@ -292,7 +292,7 @@ "onboardingBadgeText": "Nyhed", "resourceLoadingAccessibilityLabel": "Indlæser {resourceNamePlural}…", "selectAllLabel": "Vælg alle {resourceNamePlural}", - "selected": "{selectedItemsCount} valgt", + "selected": "{selectedItemsCount} valgt.", "undo": "Fortryd", "selectAllItems": "Vælg alle {itemsLength}+ {resourceNamePlural}", "selectItem": "Vælg {resourceName}", diff --git a/polaris-react/locales/de.json b/polaris-react/locales/de.json index fc1da8a8467..a6f3621f7a5 100644 --- a/polaris-react/locales/de.json +++ b/polaris-react/locales/de.json @@ -280,7 +280,7 @@ "defaultItemSingular": "Artikel", "defaultItemPlural": "Artikel", "allItemsSelected": "Alle {itemsLength}+ {resourceNamePlural} wurden ausgewählt.", - "selected": "{selectedItemsCount} ausgewählt", + "selected": "{selectedItemsCount} ausgewählt.", "a11yCheckboxDeselectAllSingle": "Auswahl für {resourceNameSingular} aufheben", "a11yCheckboxSelectAllSingle": "{resourceNameSingular} auswählen", "a11yCheckboxDeselectAllMultiple": "Auswahl für alle {itemsLength} {resourceNamePlural} aufheben", @@ -292,7 +292,7 @@ "onboardingBadgeText": "Neu", "resourceLoadingAccessibilityLabel": "{resourceNamePlural} werden geladen ...", "selectAllLabel": "Alle {resourceNamePlural} auswählen", - "selected": "{selectedItemsCount} ausgewählt", + "selected": "{selectedItemsCount} ausgewählt.", "undo": "Rückgängig machen", "selectAllItems": "Alle {itemsLength}+ {resourceNamePlural} auswählen", "selectItem": "{resourceName} auswählen", diff --git a/polaris-react/locales/es.json b/polaris-react/locales/es.json index 9835f87ab5f..7b7336331b6 100644 --- a/polaris-react/locales/es.json +++ b/polaris-react/locales/es.json @@ -281,7 +281,7 @@ "defaultItemSingular": "Artículo", "defaultItemPlural": "Artículos", "allItemsSelected": "Hay más de {itemsLength} {resourceNamePlural} seleccionados.", - "selected": "Seleccionados: {selectedItemsCount}", + "selected": "Seleccionados: {selectedItemsCount}.", "a11yCheckboxDeselectAllSingle": "Deseleccionar {resourceNameSingular}", "a11yCheckboxSelectAllSingle": "Seleccionar {resourceNameSingular}", "a11yCheckboxDeselectAllMultiple": "Deseleccionar {itemsLength} {resourceNamePlural}", @@ -293,7 +293,7 @@ "onboardingBadgeText": "Nuevo", "resourceLoadingAccessibilityLabel": "Cargando {resourceNamePlural}...", "selectAllLabel": "Seleccionar los recursos de {resourceNamePlural}", - "selected": "Seleccionados: {selectedItemsCount}", + "selected": "Seleccionados: {selectedItemsCount}.", "undo": "Deshacer", "selectAllItems": "Seleccionar los más de {itemsLength} recursos de {resourceNamePlural}", "selectItem": "Seleccionar {resourceName}", diff --git a/polaris-react/locales/fi.json b/polaris-react/locales/fi.json index b371bed95b1..d1ee0a4317e 100644 --- a/polaris-react/locales/fi.json +++ b/polaris-react/locales/fi.json @@ -280,7 +280,7 @@ "defaultItemSingular": "Tuote", "defaultItemPlural": "Tuotteet", "allItemsSelected": "Kaikki {itemsLength} ja {resourceNamePlural} on valittu.", - "selected": "{selectedItemsCount} valittu", + "selected": "{selectedItemsCount} valittu.", "a11yCheckboxDeselectAllSingle": "Poista valinta kohteesta {resourceNameSingular}", "a11yCheckboxSelectAllSingle": "Valitse {resourceNameSingular}", "a11yCheckboxDeselectAllMultiple": "Poista kaikkien valinta: {itemsLength} x {resourceNamePlural}", @@ -292,7 +292,7 @@ "onboardingBadgeText": "Uusi", "resourceLoadingAccessibilityLabel": "Ladataan {resourceNamePlural}…", "selectAllLabel": "Valitse kaikki {resourceNamePlural}", - "selected": "{selectedItemsCount} valittu", + "selected": "{selectedItemsCount} valittu.", "undo": "Peru", "selectAllItems": "Valitse kaikki {itemsLength} ja {resourceNamePlural}", "selectItem": "Valitse {resourceName}", diff --git a/polaris-react/locales/fr.json b/polaris-react/locales/fr.json index e3173de5542..8cf593c37fc 100644 --- a/polaris-react/locales/fr.json +++ b/polaris-react/locales/fr.json @@ -281,7 +281,7 @@ "defaultItemSingular": "Article", "defaultItemPlural": "Articles", "allItemsSelected": "La totalité des {itemsLength}+ {resourceNamePlural} sont sélectionnés.", - "selected": "{selectedItemsCount} sélectionné(s)", + "selected": "{selectedItemsCount} sélectionné(s)", "a11yCheckboxDeselectAllSingle": "Désélectionner {resourceNameSingular}", "a11yCheckboxSelectAllSingle": "Sélectionner {resourceNameSingular}", "a11yCheckboxDeselectAllMultiple": "Désélectionner la totalité des {itemsLength} {resourceNamePlural}", @@ -293,7 +293,7 @@ "onboardingBadgeText": "Nouveau", "resourceLoadingAccessibilityLabel": "Chargement de {resourceNamePlural} en cours…", "selectAllLabel": "Sélectionner la totalité des {resourceNamePlural}", - "selected": "{selectedItemsCount} sélectionné(s)", + "selected": "{selectedItemsCount} sélectionné(s)", "undo": "Annuler", "selectAllItems": "Sélectionner la totalité des {itemsLength}+ {resourceNamePlural}", "selectItem": "Sélectionner {resourceName}", diff --git a/polaris-react/locales/it.json b/polaris-react/locales/it.json index 90c7c927d2c..2d06d35a596 100644 --- a/polaris-react/locales/it.json +++ b/polaris-react/locales/it.json @@ -281,7 +281,7 @@ "defaultItemSingular": "Articolo", "defaultItemPlural": "Articoli", "allItemsSelected": "Tutti gli oltre {itemsLength} {resourceNamePlural} sono selezionati.", - "selected": "{selectedItemsCount} selezionati", + "selected": "{selectedItemsCount} selezionati.", "a11yCheckboxDeselectAllSingle": "Deseleziona {resourceNameSingular}", "a11yCheckboxSelectAllSingle": "Seleziona {resourceNameSingular}", "a11yCheckboxDeselectAllMultiple": "Deseleziona tutto: {itemsLength} {resourceNamePlural}", @@ -293,7 +293,7 @@ "onboardingBadgeText": "Novità", "resourceLoadingAccessibilityLabel": "Caricamento {resourceNamePlural} in corso", "selectAllLabel": "Seleziona tutto: {resourceNamePlural}", - "selected": "{selectedItemsCount} selezionati", + "selected": "{selectedItemsCount} selezionati.", "undo": "Annulla", "selectAllItems": "Seleziona tutti i {itemsLength}+ {resourceNamePlural}", "selectItem": "Seleziona {resourceName}", diff --git a/polaris-react/locales/ja.json b/polaris-react/locales/ja.json index 95cf2652fc8..ff7c76f2f91 100644 --- a/polaris-react/locales/ja.json +++ b/polaris-react/locales/ja.json @@ -280,7 +280,7 @@ "defaultItemSingular": "アイテム", "defaultItemPlural": "アイテム", "allItemsSelected": "すべての{itemsLength}+{resourceNamePlural}が選択されています。", - "selected": "{selectedItemsCount}を選択済み", + "selected": "{selectedItemsCount}個を選択済み。", "a11yCheckboxDeselectAllSingle": "{resourceNameSingular}の選択を解除する", "a11yCheckboxSelectAllSingle": "{resourceNameSingular}を選択する", "a11yCheckboxDeselectAllMultiple": "すべての{itemsLength}の{resourceNamePlural}の選択を解除する", @@ -292,7 +292,7 @@ "onboardingBadgeText": "新規", "resourceLoadingAccessibilityLabel": "{resourceNamePlural}を読み込んでいます...", "selectAllLabel": "すべての{resourceNamePlural}を選択する", - "selected": "{selectedItemsCount}を選択済み", + "selected": "{selectedItemsCount}個を選択済み。", "undo": "元に戻す", "selectAllItems": "すべての{itemsLength}+{resourceNamePlural}を選択する", "selectItem": "{resourceName}を選択する", diff --git a/polaris-react/locales/ko.json b/polaris-react/locales/ko.json index fc5e494a590..469b6a9c633 100644 --- a/polaris-react/locales/ko.json +++ b/polaris-react/locales/ko.json @@ -280,7 +280,7 @@ "defaultItemSingular": "품목", "defaultItemPlural": "품목", "allItemsSelected": "길이가 {itemsLength} 이상인 모든 {resourceNamePlural}이(가) 선택되었습니다.", - "selected": "{selectedItemsCount}개 선택됨", + "selected": "{selectedItemsCount}개가 선택되었습니다.", "a11yCheckboxDeselectAllSingle": "{resourceNameSingular} 선택 취소", "a11yCheckboxSelectAllSingle": "{resourceNameSingular} 선택", "a11yCheckboxDeselectAllMultiple": "{itemsLength}개의 모든 {resourceNamePlural} 선택 취소", @@ -292,7 +292,7 @@ "onboardingBadgeText": "신규", "resourceLoadingAccessibilityLabel": "{resourceNamePlural} 로드 중...", "selectAllLabel": "{resourceNamePlural} 모두 선택", - "selected": "{selectedItemsCount}개 선택됨", + "selected": "{selectedItemsCount}개가 선택되었습니다.", "undo": "실행 취소", "selectAllItems": "길이가 {itemsLength} 이상인 모든 {resourceNamePlural} 선택", "selectItem": "{resourceName} 선택", diff --git a/polaris-react/locales/nb.json b/polaris-react/locales/nb.json index c48e1c3c7ea..6a3e63391d0 100644 --- a/polaris-react/locales/nb.json +++ b/polaris-react/locales/nb.json @@ -280,7 +280,7 @@ "defaultItemSingular": "Vare", "defaultItemPlural": "Varer", "allItemsSelected": "Alle {itemsLength} + {resourceNamePlural} er valgt.", - "selected": "{selectedItemsCount} valgt", + "selected": "{selectedItemsCount} valgt.", "a11yCheckboxDeselectAllSingle": "Opphev valg av {resourceNameSingular}", "a11yCheckboxSelectAllSingle": "Velg {resourceNameSingular}", "a11yCheckboxDeselectAllMultiple": "Opphev alle valg av {itemsLength} {resourceNamePlural}", @@ -292,7 +292,7 @@ "onboardingBadgeText": "Ny", "resourceLoadingAccessibilityLabel": "Laster inn {resourceNamePlural} …", "selectAllLabel": "Velg alle {resourceNamePlural}", - "selected": "{selectedItemsCount} valgt", + "selected": "{selectedItemsCount} valgt.", "undo": "Angre", "selectAllItems": "Velg alle {itemsLength} {resourceNamePlural}", "selectItem": "Velg {resourceName}", diff --git a/polaris-react/locales/nl.json b/polaris-react/locales/nl.json index 2d802b3d2a1..17789d79639 100644 --- a/polaris-react/locales/nl.json +++ b/polaris-react/locales/nl.json @@ -280,7 +280,7 @@ "defaultItemSingular": "Artikel", "defaultItemPlural": "Artikelen", "allItemsSelected": "Alle {itemsLength}+ {resourceNamePlural} zijn geselecteerd.", - "selected": "{selectedItemsCount} geselecteerd", + "selected": "{selectedItemsCount} geselecteerd.", "a11yCheckboxDeselectAllSingle": "{resourceNameSingular} deselecteren", "a11yCheckboxSelectAllSingle": "{resourceNameSingular} selecteren", "a11yCheckboxDeselectAllMultiple": "Alle {itemsLength} {resourceNamePlural} deselecteren", @@ -292,7 +292,7 @@ "onboardingBadgeText": "Nieuw", "resourceLoadingAccessibilityLabel": "{resourceNamePlural} laden...", "selectAllLabel": "Alle {resourceNamePlural} selecteren", - "selected": "{selectedItemsCount} geselecteerd", + "selected": "{selectedItemsCount} geselecteerd.", "undo": "Ongedaan maken", "selectAllItems": "Alle {itemsLength}+ {resourceNamePlural} selecteren", "selectItem": "{resourceName} selecteren", diff --git a/polaris-react/locales/pl.json b/polaris-react/locales/pl.json index 3abe2fb0590..77dd951bc59 100644 --- a/polaris-react/locales/pl.json +++ b/polaris-react/locales/pl.json @@ -282,7 +282,7 @@ "defaultItemSingular": "Pozycja", "defaultItemPlural": "Pozycje", "allItemsSelected": "Wybrano wszystkie {itemsLength}+ {resourceNamePlural}.", - "selected": "Wybrano {selectedItemsCount}", + "selected": "Wybrano {selectedItemsCount}.", "a11yCheckboxDeselectAllSingle": "Usuń wybór {resourceNameSingular}", "a11yCheckboxSelectAllSingle": "Wybierz {resourceNameSingular}", "a11yCheckboxDeselectAllMultiple": "Odznacz wszystkie {itemsLength} {resourceNamePlural}", @@ -294,7 +294,7 @@ "onboardingBadgeText": "Nowy", "resourceLoadingAccessibilityLabel": "Ładowanie {resourceNamePlural}...", "selectAllLabel": "Wybierz wszystkie {resourceNamePlural}", - "selected": "Wybrano {selectedItemsCount}", + "selected": "Wybrano {selectedItemsCount}.", "undo": "Cofnij", "selectAllItems": "Wybierz wszystkie {itemsLength}+ {resourceNamePlural}", "selectItem": "Wybierz {resourceName}", diff --git a/polaris-react/locales/pt-BR.json b/polaris-react/locales/pt-BR.json index 7d4b93d0a56..306682badb2 100644 --- a/polaris-react/locales/pt-BR.json +++ b/polaris-react/locales/pt-BR.json @@ -281,7 +281,7 @@ "defaultItemSingular": "Item", "defaultItemPlural": "Itens", "allItemsSelected": "Todos os {itemsLength}+ {resourceNamePlural} estão selecionados.", - "selected": "{selectedItemsCount} selecionados", + "selected": "{selectedItemsCount} selecionados.", "a11yCheckboxDeselectAllSingle": "Desmarcar {resourceNameSingular}", "a11yCheckboxSelectAllSingle": "Selecionar {resourceNameSingular}", "a11yCheckboxDeselectAllMultiple": "Desmarcar todos os {itemsLength} {resourceNamePlural}", @@ -293,7 +293,7 @@ "onboardingBadgeText": "Novo", "resourceLoadingAccessibilityLabel": "Carregando {resourceNamePlural}…", "selectAllLabel": "Selecionar todos os {resourceNamePlural}", - "selected": "{selectedItemsCount} selecionados", + "selected": "{selectedItemsCount} selecionados.", "undo": "Desfazer", "selectAllItems": "Selecionar todos os {resourceNamePlural} maiores que {itemsLength}", "selectItem": "Selecionar {resourceName}", diff --git a/polaris-react/locales/sv.json b/polaris-react/locales/sv.json index ece9a56c6bd..2150e932711 100644 --- a/polaris-react/locales/sv.json +++ b/polaris-react/locales/sv.json @@ -280,7 +280,7 @@ "defaultItemSingular": "Artikel", "defaultItemPlural": "Artiklar", "allItemsSelected": "Alla {itemsLength}+ {resourceNamePlural} har valts.", - "selected": "{selectedItemsCount} har valts", + "selected": "{selectedItemsCount} har valts.", "a11yCheckboxDeselectAllSingle": "Avmarkera {resourceNameSingular}", "a11yCheckboxSelectAllSingle": "Välj {resourceNameSingular}", "a11yCheckboxDeselectAllMultiple": "Avmarkera alla {itemsLength} {resourceNamePlural}", @@ -292,7 +292,7 @@ "onboardingBadgeText": "Nytt", "resourceLoadingAccessibilityLabel": "Laddar {resourceNamePlural}", "selectAllLabel": "Välj alla {resourceNamePlural}", - "selected": "{selectedItemsCount} har valts", + "selected": "{selectedItemsCount} har valts.", "undo": "Ångra", "selectAllItems": "Välj alla {itemsLength}+ {resourceNamePlural}", "selectItem": "Välj {resourceName}", diff --git a/polaris-react/locales/tr.json b/polaris-react/locales/tr.json index ca72a7a721f..417bd9ca3f4 100644 --- a/polaris-react/locales/tr.json +++ b/polaris-react/locales/tr.json @@ -280,7 +280,7 @@ "defaultItemSingular": "Ürün", "defaultItemPlural": "Ürünler", "allItemsSelected": "Şunların tümü seçildi: {itemsLength}+ {resourceNamePlural}.", - "selected": "{selectedItemsCount} adet seçildi", + "selected": "{selectedItemsCount} adet seçildi.", "a11yCheckboxDeselectAllSingle": "{resourceNameSingular} kaynağının seçimini kaldır", "a11yCheckboxSelectAllSingle": "{resourceNameSingular} kaynağını seç", "a11yCheckboxDeselectAllMultiple": "Şunların tümünün seçimini kaldır: {itemsLength} {resourceNamePlural}", @@ -292,7 +292,7 @@ "onboardingBadgeText": "Yeni", "resourceLoadingAccessibilityLabel": "{resourceNamePlural} yükleniyor…", "selectAllLabel": "{resourceNamePlural} kaynaklarının tümünü seç", - "selected": "{selectedItemsCount} adet seçildi", + "selected": "{selectedItemsCount} adet seçildi.", "undo": "Geri al", "selectAllItems": "Şunların tümünü seç: {itemsLength}+ {resourceNamePlural}", "selectItem": "{resourceName} kaynağını seç", diff --git a/polaris-react/locales/vi.json b/polaris-react/locales/vi.json index 89d6f65ee08..927ae85ef7d 100644 --- a/polaris-react/locales/vi.json +++ b/polaris-react/locales/vi.json @@ -280,7 +280,7 @@ "defaultItemSingular": "Mặt hàng", "defaultItemPlural": "Mặt hàng", "allItemsSelected": "Đã chọn tất cả {itemsLength}+ {resourceNamePlural}.", - "selected": "Đã chọn {selectedItemsCount}", + "selected": "Đã chọn {selectedItemsCount}.", "a11yCheckboxDeselectAllSingle": "Bỏ chọn {resourceNameSingular}", "a11yCheckboxSelectAllSingle": "Chọn {resourceNameSingular}", "a11yCheckboxDeselectAllMultiple": "Bỏ chọn tất cả {itemsLength} {resourceNamePlural}", @@ -292,7 +292,7 @@ "onboardingBadgeText": "Mới", "resourceLoadingAccessibilityLabel": "Đang tải {resourceNamePlural}…", "selectAllLabel": "Chọn tất cả {resourceNamePlural}", - "selected": "Đã chọn {selectedItemsCount}", + "selected": "Đã chọn {selectedItemsCount}.", "undo": "Hoàn tác", "selectAllItems": "Chọn tất cả {itemsLength}+ {resourceNamePlural}", "selectItem": "Chọn {resourceName}", diff --git a/polaris-react/locales/zh-CN.json b/polaris-react/locales/zh-CN.json index 32f3c4e9667..a70fcf85e93 100644 --- a/polaris-react/locales/zh-CN.json +++ b/polaris-react/locales/zh-CN.json @@ -280,7 +280,7 @@ "defaultItemSingular": "项", "defaultItemPlural": "项", "allItemsSelected": "已选择所有 {itemsLength}+ 个{resourceNamePlural}。", - "selected": "已选择 {selectedItemsCount} 个", + "selected": "已选择 {selectedItemsCount} 项。", "a11yCheckboxDeselectAllSingle": "取消选择 {resourceNameSingular}", "a11yCheckboxSelectAllSingle": "选择 {resourceNameSingular}", "a11yCheckboxDeselectAllMultiple": "取消选择所有 {itemsLength} 个 {resourceNamePlural}", @@ -292,7 +292,7 @@ "onboardingBadgeText": "新", "resourceLoadingAccessibilityLabel": "正在加载 {resourceNamePlural}…", "selectAllLabel": "选择所有 {resourceNamePlural}", - "selected": "已选择 {selectedItemsCount} 个", + "selected": "已选择 {selectedItemsCount} 项。", "undo": "撤销", "selectAllItems": "选择所有 {itemsLength}+ 个 {resourceNamePlural}", "selectItem": "选择 {resourceName}", diff --git a/polaris-react/locales/zh-TW.json b/polaris-react/locales/zh-TW.json index 348a094aae3..d5b452b71c0 100644 --- a/polaris-react/locales/zh-TW.json +++ b/polaris-react/locales/zh-TW.json @@ -280,7 +280,7 @@ "defaultItemSingular": "品項", "defaultItemPlural": "品項", "allItemsSelected": "已選取全部 {itemsLength} + {resourceNamePlural}。", - "selected": "已選取 {selectedItemsCount} 項", + "selected": "已選取 {selectedItemsCount} 個。", "a11yCheckboxDeselectAllSingle": "取消選取 {resourceNameSingular}", "a11yCheckboxSelectAllSingle": "選取 {resourceNameSingular}", "a11yCheckboxDeselectAllMultiple": "取消選取全部 {itemsLength} {resourceNamePlural}", @@ -292,7 +292,7 @@ "onboardingBadgeText": "全新功能", "resourceLoadingAccessibilityLabel": "正在載入 {resourceNamePlural}......", "selectAllLabel": "選取所有 {resourceNamePlural}", - "selected": "已選取 {selectedItemsCount} 項", + "selected": "已選取 {selectedItemsCount} 個。", "undo": "復原", "selectAllItems": "選取全部 {itemsLength} + {resourceNamePlural}", "selectItem": "選取 {resourceName}", From 5f44bb244879c8e90e869e56de199b806bee1fee Mon Sep 17 00:00:00 2001 From: "translation-platform[bot]" <34770790+translation-platform[bot]@users.noreply.github.com> Date: Tue, 22 Nov 2022 17:02:25 +0000 Subject: [PATCH 28/32] Update 1 translation file --- polaris-react/locales/pt-PT.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/polaris-react/locales/pt-PT.json b/polaris-react/locales/pt-PT.json index f8dc48c10b0..582b690d4d7 100644 --- a/polaris-react/locales/pt-PT.json +++ b/polaris-react/locales/pt-PT.json @@ -281,7 +281,7 @@ "defaultItemSingular": "Item", "defaultItemPlural": "Itens", "allItemsSelected": "Todos os itens de {resourceNamePlural} de {itemsLength}+ foram selecionados.", - "selected": "{selectedItemsCount} selecionada", + "selected": "{selectedItemsCount} selecionados.", "a11yCheckboxDeselectAllSingle": "Desselecionar {resourceNameSingular}", "a11yCheckboxSelectAllSingle": "Selecionar {resourceNameSingular}", "a11yCheckboxDeselectAllMultiple": "Desselecionar tudo {itemsLength} {resourceNamePlural}", @@ -293,7 +293,7 @@ "onboardingBadgeText": "Novo", "resourceLoadingAccessibilityLabel": "A carregar {resourceNamePlural}", "selectAllLabel": "Selecionar tudo {resourceNamePlural}", - "selected": "{selectedItemsCount} selecionada", + "selected": "{selectedItemsCount} selecionados.", "undo": "Anular", "selectAllItems": "Selecionar todos os itens de {resourceNamePlural} de {itemsLength}+", "selectItem": "Selecionar {resourceName}", From ce9d46d09ad700cf6474e22529610c6432e29f60 Mon Sep 17 00:00:00 2001 From: Marc Thomas Date: Thu, 24 Nov 2022 16:18:04 +0000 Subject: [PATCH 29/32] chore: initial feedback from review --- .changeset/odd-spoons-dance.md | 2 +- .../src/components/BulkActions/BulkActions.scss | 1 + .../BulkActions/tests/BulkActions.test.tsx | 12 ------------ .../src/components/IndexTable/IndexTable.tsx | 9 ++++++--- .../components/ResourceList/ResourceList.tsx | 17 ++++++++--------- 5 files changed, 16 insertions(+), 25 deletions(-) diff --git a/.changeset/odd-spoons-dance.md b/.changeset/odd-spoons-dance.md index bc35969d440..5b38777d2cf 100644 --- a/.changeset/odd-spoons-dance.md +++ b/.changeset/odd-spoons-dance.md @@ -2,4 +2,4 @@ '@shopify/polaris': minor --- -Separate BulkActions and SelectAllActions for new bulk selection experience" +Separated BulkActions and SelectAllActions for new sticky bulk actions experience diff --git a/polaris-react/src/components/BulkActions/BulkActions.scss b/polaris-react/src/components/BulkActions/BulkActions.scss index f366ba9115b..751b56cae32 100644 --- a/polaris-react/src/components/BulkActions/BulkActions.scss +++ b/polaris-react/src/components/BulkActions/BulkActions.scss @@ -14,6 +14,7 @@ $bulk-actions-button-stacking-order: ( width: 100%; justify-content: center; transition: var(--p-duration-250) var(--p-ease-in); + transition-property: transform, opacity; transform: translateY(120px); padding: 0 var(--p-space-4); diff --git a/polaris-react/src/components/BulkActions/tests/BulkActions.test.tsx b/polaris-react/src/components/BulkActions/tests/BulkActions.test.tsx index d73535207cc..c2189a2f641 100644 --- a/polaris-react/src/components/BulkActions/tests/BulkActions.test.tsx +++ b/polaris-react/src/components/BulkActions/tests/BulkActions.test.tsx @@ -9,7 +9,6 @@ import { BulkActionButtonProps, } from '../components'; import {BulkAction, BulkActions, BulkActionsProps} from '../BulkActions'; -import styles from '../BulkActions.scss'; interface Props { bulkActions: BulkActionButtonProps['content'][]; @@ -323,17 +322,6 @@ describe('', () => { expect(spy).toHaveBeenCalledTimes(1); }); }); - - describe('className', () => { - it('renders with the Group className', () => { - const bulkActions = mountWithApp( - , - ); - expect(bulkActions).toContainReactComponent('div', { - className: expect.stringContaining(styles.Group), - }); - }); - }); }); describe('buttongroup', () => { diff --git a/polaris-react/src/components/IndexTable/IndexTable.tsx b/polaris-react/src/components/IndexTable/IndexTable.tsx index c54e34a3df2..ebd40f346d3 100644 --- a/polaris-react/src/components/IndexTable/IndexTable.tsx +++ b/polaris-react/src/components/IndexTable/IndexTable.tsx @@ -546,11 +546,14 @@ function IndexTableBase({ shouldShowBulkActions && !condensed ? (
    ({ registerCheckableButtons: handleCheckableButtonRegistration, }; + const resourceListWrapperClasses = classNames( + styles.ResourceListWrapper, + Boolean(bulkActionsMarkup) && + selectMode && + styles.ResourceListWrapperWithBulkActions, + ); + return ( -
    +
    {filterControlMarkup} {headerMarkup} {listMarkup} From bc11548ea2993d7d03509eba8c0f21364fa7a09f Mon Sep 17 00:00:00 2001 From: Marc Thomas Date: Fri, 25 Nov 2022 15:51:14 +0000 Subject: [PATCH 30/32] chore:export select all actions --- polaris-react/src/components/index.ts | 1 - polaris-react/src/index.ts | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) delete mode 100644 polaris-react/src/components/index.ts diff --git a/polaris-react/src/components/index.ts b/polaris-react/src/components/index.ts deleted file mode 100644 index f28de61ee83..00000000000 --- a/polaris-react/src/components/index.ts +++ /dev/null @@ -1 +0,0 @@ -export {SelectAllActions} from './SelectAllActions'; diff --git a/polaris-react/src/index.ts b/polaris-react/src/index.ts index 92507ddada9..db6a31e1989 100644 --- a/polaris-react/src/index.ts +++ b/polaris-react/src/index.ts @@ -316,6 +316,9 @@ export {ScrollLock} from './components/ScrollLock'; export {Select} from './components/Select'; export type {SelectProps, SelectOption, SelectGroup} from './components/Select'; +export {SelectAllActions} from './components/SelectAllActions'; +export type {SelectAllActionsProps} from './components/SelectAllActions'; + export {SettingToggle} from './components/SettingToggle'; export type {SettingToggleProps} from './components/SettingToggle'; From 3e34ede1fb1455b77528e579034768f8516a33e4 Mon Sep 17 00:00:00 2001 From: Marc Thomas Date: Mon, 28 Nov 2022 14:40:37 +0000 Subject: [PATCH 31/32] chore: updates from review --- .../components/BulkActions/BulkActions.scss | 1 + .../hooks/use-is-bulk-actions-sticky.ts | 35 ++++++++------- .../CheckableButton/CheckableButton.tsx | 45 +++++++++---------- .../components/ResourceList/ResourceList.scss | 1 - .../components/ResourceList/ResourceList.tsx | 24 ++-------- .../SelectAllActions/SelectAllActions.scss | 1 + .../SelectAllActions/SelectAllActions.tsx | 30 +++++++------ .../src/utilities/resource-list/context.ts | 8 +--- .../src/utilities/resource-list/index.ts | 6 +-- .../src/utilities/resource-list/types.ts | 4 -- 10 files changed, 67 insertions(+), 88 deletions(-) diff --git a/polaris-react/src/components/BulkActions/BulkActions.scss b/polaris-react/src/components/BulkActions/BulkActions.scss index 751b56cae32..c5c13cad303 100644 --- a/polaris-react/src/components/BulkActions/BulkActions.scss +++ b/polaris-react/src/components/BulkActions/BulkActions.scss @@ -17,6 +17,7 @@ $bulk-actions-button-stacking-order: ( transition-property: transform, opacity; transform: translateY(120px); padding: 0 var(--p-space-4); + will-change: transform, opacity; &.Group-not-sticky { transform: none; diff --git a/polaris-react/src/components/BulkActions/hooks/use-is-bulk-actions-sticky.ts b/polaris-react/src/components/BulkActions/hooks/use-is-bulk-actions-sticky.ts index 7a0eb690927..0cd8e3b7c4d 100644 --- a/polaris-react/src/components/BulkActions/hooks/use-is-bulk-actions-sticky.ts +++ b/polaris-react/src/components/BulkActions/hooks/use-is-bulk-actions-sticky.ts @@ -7,6 +7,8 @@ const DEBOUNCE_PERIOD = 250; const PADDING_IN_SELECT_MODE = 100; export function useIsBulkActionsSticky(selectMode: boolean) { + const hasIOSupport = + typeof window !== 'undefined' && Boolean(window.IntersectionObserver); const [isBulkActionsSticky, setIsSticky] = useState(false); const [bulkActionsAbsoluteOffset, setBulkActionsAbsoluteOffset] = useState(0); const [bulkActionsMaxWidth, setBulkActionsMaxWidth] = useState(0); @@ -14,6 +16,21 @@ export function useIsBulkActionsSticky(selectMode: boolean) { const bulkActionsIntersectionRef = useRef(null); const tableMeasurerRef = useRef(null); + const handleIntersect = (entries: IntersectionObserverEntry[]) => { + entries.forEach((entry: IntersectionObserverEntry) => { + setIsSticky(!entry.isIntersecting); + }); + }; + + const options = { + root: null, + rootMargin: '0px', + threshold: 1, + }; + const observerRef = useRef( + hasIOSupport ? new IntersectionObserver(handleIntersect, options) : null, + ); + useEffect(() => { function computeTableDimensions() { const node = tableMeasurerRef.current; @@ -52,22 +69,10 @@ export function useIsBulkActionsSticky(selectMode: boolean) { }, [tableMeasurerRef, selectMode]); useEffect(() => { - const hasIOSupport = Boolean(window.IntersectionObserver); - if (!hasIOSupport) { + const observer = observerRef.current; + if (!observer) { return; } - const handleIntersect = (entries: IntersectionObserverEntry[]) => { - entries.forEach((entry: IntersectionObserverEntry) => { - setIsSticky(!entry.isIntersecting); - }); - }; - - const options = { - root: null, - rootMargin: '0px', - threshold: 1, - }; - const observer = new IntersectionObserver(handleIntersect, options); const node = bulkActionsIntersectionRef.current; @@ -76,7 +81,7 @@ export function useIsBulkActionsSticky(selectMode: boolean) { } return () => { - observer.disconnect(); + observer?.disconnect(); }; }, [bulkActionsIntersectionRef]); diff --git a/polaris-react/src/components/CheckableButton/CheckableButton.tsx b/polaris-react/src/components/CheckableButton/CheckableButton.tsx index 558ebac8153..277ec67b855 100644 --- a/polaris-react/src/components/CheckableButton/CheckableButton.tsx +++ b/polaris-react/src/components/CheckableButton/CheckableButton.tsx @@ -1,12 +1,8 @@ -import React, {useContext, useRef, useEffect} from 'react'; +import React, {useRef, useImperativeHandle, forwardRef} from 'react'; import type {CheckboxHandles} from '../../types'; import {classNames} from '../../utilities/css'; import {Checkbox} from '../Checkbox'; -import { - ResourceListContext, - CheckableButtonKey, -} from '../../utilities/resource-list'; import styles from './CheckableButton.scss'; @@ -16,28 +12,31 @@ export interface CheckableButtonProps { selected?: boolean | 'indeterminate'; disabled?: boolean; onToggleAll?(): void; - ariaLive?: 'off' | 'assertive' | 'polite'; + ariaLive?: 'off' | 'polite'; } -export function CheckableButton({ - accessibilityLabel, - label = '', - onToggleAll, - selected, - disabled, - ariaLive, -}: CheckableButtonProps) { +export const CheckableButton = forwardRef(function CheckableButton( + { + accessibilityLabel, + label = '', + onToggleAll, + selected, + disabled, + ariaLive, + }: CheckableButtonProps, + ref, +) { const checkBoxRef = useRef(null); - const {registerCheckableButtons} = useContext(ResourceListContext); + function focus() { + checkBoxRef?.current?.focus(); + } - const currentKey: CheckableButtonKey = 'plain'; - - useEffect(() => { - if (checkBoxRef.current && registerCheckableButtons) { - registerCheckableButtons(currentKey, checkBoxRef.current); - } - }, [currentKey, registerCheckableButtons]); + useImperativeHandle(ref, () => { + return { + focus, + }; + }); const className = classNames(styles.CheckableButton); @@ -58,4 +57,4 @@ export function CheckableButton({
    ); -} +}); diff --git a/polaris-react/src/components/ResourceList/ResourceList.scss b/polaris-react/src/components/ResourceList/ResourceList.scss index b1c7e05731f..036592131a6 100644 --- a/polaris-react/src/components/ResourceList/ResourceList.scss +++ b/polaris-react/src/components/ResourceList/ResourceList.scss @@ -155,7 +155,6 @@ $breakpoints-empty-search-results-height-up: '(min-height: #{breakpoint(600px)}) .BulkActionsWrapper { z-index: resource-list(bulk-actions-wrapper-stacking-order); - visibility: visible; position: absolute; left: 0; width: 100%; diff --git a/polaris-react/src/components/ResourceList/ResourceList.tsx b/polaris-react/src/components/ResourceList/ResourceList.tsx index d1fe4eeeed2..4582d7b990a 100644 --- a/polaris-react/src/components/ResourceList/ResourceList.tsx +++ b/polaris-react/src/components/ResourceList/ResourceList.tsx @@ -11,7 +11,6 @@ import {EnableSelectionMinor} from '@shopify/polaris-icons'; import {tokens, toPx} from '@shopify/polaris-tokens'; import {debounce} from '../../utilities/debounce'; -import type {CheckboxHandles} from '../../types'; import {classNames} from '../../utilities/css'; import {isElementOfType} from '../../utilities/components'; import {Button} from '../Button'; @@ -20,8 +19,6 @@ import {EventListener} from '../EventListener'; import {Sticky} from '../Sticky'; import {Spinner} from '../Spinner'; import { - CheckableButtonKey, - CheckableButtons, ResourceListContext, ResourceListSelectedItems, SELECT_ALL_ITEMS, @@ -161,10 +158,7 @@ export const ResourceList: ResourceListType = function ResourceList({ (x = 0) => x + 1, 0, )[1]; - - const [checkableButtons, setCheckableButtons] = useState( - new Map(), - ); + const checkableButtonRef = useRef(null); const { bulkActionsIntersectionRef, @@ -445,15 +439,6 @@ export const ResourceList: ResourceListType = function ResourceList({ return items.slice(min, max + 1).map(resolveItemId); }; - const handleCheckableButtonRegistration = ( - key: CheckableButtonKey, - button: CheckboxHandles, - ) => { - if (!checkableButtons.get(key)) { - setCheckableButtons(new Map(checkableButtons).set(key, button)); - } - }; - const handleSelectionChange = ( selected: boolean, id: string, @@ -528,15 +513,13 @@ export const ResourceList: ResourceListType = function ResourceList({ handleSelectMode(true); } - const checkbox: CheckboxHandles | undefined = checkableButtons.get('plain'); - if (onSelectionChange) { onSelectionChange(newlySelectedItems); } // setTimeout ensures execution after the Transition on BulkActions setTimeout(() => { - checkbox && checkbox.focus(); + checkableButtonRef?.current?.focus(); }, 0); }; @@ -551,6 +534,7 @@ export const ResourceList: ResourceListType = function ResourceList({ paginatedSelectAllAction={paginatedSelectAllAction()} paginatedSelectAllText={paginatedSelectAllText()} disabled={loading} + ref={checkableButtonRef} />
    ) : null; @@ -629,6 +613,7 @@ export const ResourceList: ResourceListType = function ResourceList({ label={headerTitle()} onToggleAll={handleToggleAll} disabled={loading} + ref={checkableButtonRef} />
    ) : null; @@ -749,7 +734,6 @@ export const ResourceList: ResourceListType = function ResourceList({ resourceName, loading, onSelectionChange: handleSelectionChange, - registerCheckableButtons: handleCheckableButtonRegistration, }; const resourceListWrapperClasses = classNames( diff --git a/polaris-react/src/components/SelectAllActions/SelectAllActions.scss b/polaris-react/src/components/SelectAllActions/SelectAllActions.scss index c610628b31c..4e4674d5556 100644 --- a/polaris-react/src/components/SelectAllActions/SelectAllActions.scss +++ b/polaris-react/src/components/SelectAllActions/SelectAllActions.scss @@ -5,6 +5,7 @@ gap: var(--p-space-025); align-items: center; justify-content: flex-start; + will-change: opacity, display; } .SelectAllActions-entering, diff --git a/polaris-react/src/components/SelectAllActions/SelectAllActions.tsx b/polaris-react/src/components/SelectAllActions/SelectAllActions.tsx index 3fd5c3b1178..8a3dc9df87b 100644 --- a/polaris-react/src/components/SelectAllActions/SelectAllActions.tsx +++ b/polaris-react/src/components/SelectAllActions/SelectAllActions.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, {forwardRef} from 'react'; import {Transition} from 'react-transition-group'; import {classNames} from '../../utilities/css'; @@ -9,7 +9,7 @@ import {CheckableButton} from '../CheckableButton'; import styles from './SelectAllActions.scss'; type TransitionStatus = 'entering' | 'entered' | 'exiting' | 'exited'; -type AriaLive = 'off' | 'assertive' | 'polite' | undefined; +type AriaLive = 'off' | 'polite' | undefined; export interface SelectAllActionsProps { /** Visually hidden text for screen readers */ @@ -30,16 +30,19 @@ export interface SelectAllActionsProps { onToggleAll?(): void; } -export function SelectAllActions({ - accessibilityLabel, - label, - selected, - selectMode, - paginatedSelectAllText, - paginatedSelectAllAction, - disabled, - onToggleAll, -}: SelectAllActionsProps) { +export const SelectAllActions = forwardRef(function SelectAllActions( + { + accessibilityLabel, + label, + selected, + selectMode, + paginatedSelectAllText, + paginatedSelectAllAction, + disabled, + onToggleAll, + }: SelectAllActionsProps, + ref, +) { const paginatedSelectAllActionMarkup = paginatedSelectAllAction ? ( @@ -86,4 +90,4 @@ export function SelectAllActions({ ); return markup; -} +}); diff --git a/polaris-react/src/utilities/resource-list/context.ts b/polaris-react/src/utilities/resource-list/context.ts index 262f02a0791..4a7c9062d5d 100644 --- a/polaris-react/src/utilities/resource-list/context.ts +++ b/polaris-react/src/utilities/resource-list/context.ts @@ -1,15 +1,9 @@ import {createContext} from 'react'; -import type {CheckboxHandles} from '../../types'; - -import type {ResourceListSelectedItems, CheckableButtonKey} from './types'; +import type {ResourceListSelectedItems} from './types'; // This is internal, but TS throws a build-time error if we don't export it export interface ResourceListContextType { - registerCheckableButtons?( - key: CheckableButtonKey, - button: CheckboxHandles, - ): void; selectMode?: boolean; selectable?: boolean; selectedItems?: ResourceListSelectedItems; diff --git a/polaris-react/src/utilities/resource-list/index.ts b/polaris-react/src/utilities/resource-list/index.ts index cbe84e3d554..f52ca01ba8f 100644 --- a/polaris-react/src/utilities/resource-list/index.ts +++ b/polaris-react/src/utilities/resource-list/index.ts @@ -1,8 +1,4 @@ export * from './context'; export {SELECT_ALL_ITEMS} from './types'; -export type { - ResourceListSelectedItems, - CheckableButtons, - CheckableButtonKey, -} from './types'; +export type {ResourceListSelectedItems} from './types'; diff --git a/polaris-react/src/utilities/resource-list/types.ts b/polaris-react/src/utilities/resource-list/types.ts index 5bf46d9aee0..96dd31ab659 100644 --- a/polaris-react/src/utilities/resource-list/types.ts +++ b/polaris-react/src/utilities/resource-list/types.ts @@ -1,7 +1,3 @@ -import type {CheckboxHandles} from '../../types'; - export type ResourceListSelectedItems = string[] | 'All'; -export type CheckableButtonKey = 'plain'; -export type CheckableButtons = Map; export const SELECT_ALL_ITEMS = 'All'; From fab4d8a2a7588c6b7e03319a0cfef0beacd1a03f Mon Sep 17 00:00:00 2001 From: Marc Thomas Date: Wed, 30 Nov 2022 13:12:28 +0000 Subject: [PATCH 32/32] chore: remove display from will-change declaration --- .../src/components/SelectAllActions/SelectAllActions.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polaris-react/src/components/SelectAllActions/SelectAllActions.scss b/polaris-react/src/components/SelectAllActions/SelectAllActions.scss index 4e4674d5556..e73c3ce3c30 100644 --- a/polaris-react/src/components/SelectAllActions/SelectAllActions.scss +++ b/polaris-react/src/components/SelectAllActions/SelectAllActions.scss @@ -5,7 +5,7 @@ gap: var(--p-space-025); align-items: center; justify-content: flex-start; - will-change: opacity, display; + will-change: opacity; } .SelectAllActions-entering,