From ed02b49c92344039d1ced4eae74959c196b1e24a Mon Sep 17 00:00:00 2001 From: Pamela Hicks Date: Thu, 29 Apr 2021 09:35:34 -0400 Subject: [PATCH 01/12] Add last prop to Cell --- UNRELEASED.md | 17 ++++ src/components/IndexTable/IndexTable.scss | 19 ++++- src/components/IndexTable/README.md | 77 +++++++++++++++++++ .../IndexTable/components/Cell/Cell.tsx | 4 +- .../components/Cell/tests/Cell.test.tsx | 8 ++ 5 files changed, 121 insertions(+), 4 deletions(-) diff --git a/UNRELEASED.md b/UNRELEASED.md index 0c8aa79085c..289530fd2e3 100644 --- a/UNRELEASED.md +++ b/UNRELEASED.md @@ -9,6 +9,23 @@ Use [the changelog guidelines](https://git.io/polaris-changelog-guidelines) to f - Added `id` prop to `Layout` and `Heading` for hash linking ([#4307](https://github.com/Shopify/polaris-react/pull/4307)) - Added `external` prop to `Navigation.Item` component ([#4310](https://github.com/Shopify/polaris-react/pull/4310)) - Added `ariaLabelledBy` props to `Navigation` component to allow a hidden label for accessibility ([#4343](https://github.com/Shopify/polaris-react/pull/4343)) +- Prevented `KeypressListener` attaching/detaching on every render ([#4173](https://github.com/Shopify/polaris-react/pull/4173)) +- Added `animated` prop in `ProgressBar` ([#4251](https://github.com/Shopify/polaris-react/pull/4251)) +- Added `divider` prop to `Page` component ([#4260](https://github.com/Shopify/polaris-react/pull/4260)) +- Add `activator` prop to `Sheet` so the triggering element will regain focus ([#4201](https://github.com/Shopify/polaris-react/pull/4201)) +- Rename and expose Card compound components types ([#4261](https://github.com/Shopify/polaris-react/pull/4261)) +- Add `monospaced` prop to `TextField` component ([#4264](https://github.com/Shopify/polaris-react/pull/4264)) +- Add base tight spacing option to `Stack` component([#4273](https://github.com/Shopify/polaris-react/pull/4273)) +- Add `variableHeight` prop to `DropZone` so children control its height ([#4136](https://github.com/Shopify/polaris-react/pull/4136)) +- Add print styles to `Card`, `Heading`, `Layout`, `Layout.Section`, `Subheading`, `TextStyle` components ([#4142](https://github.com/Shopify/polaris-react/pull/4142)) +- Add `fullWidth` prop to `ColorPicker` so the color picker can take the full width ([#4152](https://github.com/Shopify/polaris-react/pull/4152)) +- Add `noScroll` prop to `Modal` which prevents modal contents from scrolling ([#4153](https://github.com/Shopify/polaris-react/pull/4153)) +- Added new `color` prop to ProgressBar ([#3415](https://github.com/Shopify/polaris-react/pull/3415)) +- Added `requiredIndicator` prop to `Label`, `Labelled`, `Select` and `TextField` ([#4119](https://github.com/Shopify/polaris-react/pull/4119)) +- Add `small` prop to `Modal` so that width can be decreased to 380px ([#4177](https://github.com/Shopify/polaris-react/pull/4177)) +- Add `status` prop to `IndexTable.Row` to allow table rows to specify background colors([#4146](https://github.com/Shopify/polaris-react/pull/4146)) +- Disabled `pointer-events` on the prefix and suffix elements of the `TextField` component ([#4207](https://github.com/Shopify/polaris-react/pull/4207)) +- Add `last` prop to `IndexTable.Cell` to create a sticky last cell on viewports larger than small ([#4150](https://github.com/Shopify/polaris-react/pull/4150)) ### Bug fixes diff --git a/src/components/IndexTable/IndexTable.scss b/src/components/IndexTable/IndexTable.scss index ca4b7dbee74..7b95c1e2f85 100644 --- a/src/components/IndexTable/IndexTable.scss +++ b/src/components/IndexTable/IndexTable.scss @@ -116,7 +116,8 @@ $loading-panel-height: rem(53px); // stylelint-disable-next-line selector-max-combinators, selector-max-class, selector-max-specificity &, .TableCell-first, - .TableCell-first + .TableCell { + .TableCell-first + .TableCell, + .TableCell-last { background-color: var(--p-surface-primary-selected); } } @@ -134,7 +135,8 @@ $loading-panel-height: rem(53px); // stylelint-disable-next-line selector-max-class, selector-max-combinators, selector-max-specificity &, .TableCell-first, - .TableCell-first + .TableCell { + .TableCell-first + .TableCell, + .TableCell-last { background-color: var(--p-surface-selected-hovered); } } @@ -145,7 +147,8 @@ $loading-panel-height: rem(53px); .TableHeading-first, .TableHeading-second, .TableCell-first, - .TableCell-first + .TableCell { + .TableCell-first + .TableCell, + .TableCell-last { background-color: var(--p-surface-selected); } } @@ -222,6 +225,16 @@ $loading-panel-height: rem(53px); } } +.TableCell-last { + @include breakpoint-after($breakpoint-small) { + position: sticky; + right: 0; + z-index: z-index(sticky-cell, $index-table-stacking-order); + box-shadow: rem(-1px) rem(-1px) 0 0 var(--p-divider, color('sky')); + background-color: var(--p-surface, color('white')); + } +} + .StickyTable { position: relative; top: 0; diff --git a/src/components/IndexTable/README.md b/src/components/IndexTable/README.md index 7c69e72bb47..172262a994b 100644 --- a/src/components/IndexTable/README.md +++ b/src/components/IndexTable/README.md @@ -784,6 +784,82 @@ function SimpleIndexTableExample() { } ``` +### Index table with sticky last column + +An index table with a sticky last column that stays visible on scroll. + +```jsx +function SimpleIndexTableExample() { + const customers = [ + { + id: '3411', + url: 'customers/341', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$2,400', + }, + { + id: '2561', + 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} + + + ); +} +``` + ### IndexTable with all of its elements Use as a broad example that includes most of the elements and props available to index table. @@ -1282,6 +1358,7 @@ An `IndexTableCell` is used to render a single cell within an `IndexTableRow` | Prop | Type | Description | | ----- | ------- | -------------------------------------------------------------------------------- | | flush | boolean | A boolean property indicating whether the cell should remove the default padding | +| last | boolean | A boolean property indicating whether the last cell should stay sticky | --- diff --git a/src/components/IndexTable/components/Cell/Cell.tsx b/src/components/IndexTable/components/Cell/Cell.tsx index 0a1d0a85ef5..427884c362c 100644 --- a/src/components/IndexTable/components/Cell/Cell.tsx +++ b/src/components/IndexTable/components/Cell/Cell.tsx @@ -6,12 +6,14 @@ import styles from '../../IndexTable.scss'; export interface CellProps { children?: ReactNode; flush?: boolean; + last?: boolean; } -export const Cell = memo(function Cell({children, flush}: CellProps) { +export const Cell = memo(function Cell({children, flush, last}: CellProps) { const cellClassName = classNames( styles.TableCell, flush && styles['TableCell-flush'], + last && styles['TableCell-last'], ); return {children}; diff --git a/src/components/IndexTable/components/Cell/tests/Cell.test.tsx b/src/components/IndexTable/components/Cell/tests/Cell.test.tsx index 7d55a1c919a..51dfc72f7b0 100644 --- a/src/components/IndexTable/components/Cell/tests/Cell.test.tsx +++ b/src/components/IndexTable/components/Cell/tests/Cell.test.tsx @@ -17,6 +17,14 @@ describe('', () => { className: 'TableCell TableCell-flush', }); }); + + it('applies last column styles when last prop is true', () => { + const cell = mountWithTable(); + + expect(cell).toContainReactComponent('td', { + className: 'TableCell TableCell-last', + }); + }); }); function mountWithTable(children: ReactElement) { From 5676b4b068e778e56e8e6bdc95921376043e464e Mon Sep 17 00:00:00 2001 From: Pamela Hicks Date: Mon, 28 Jun 2021 18:50:05 -0400 Subject: [PATCH 02/12] Refactor to include optional sticky last header --- src/components/IndexTable/IndexTable.scss | 43 +++++++++++++------ src/components/IndexTable/IndexTable.tsx | 5 +++ .../IndexTable/components/Cell/Cell.tsx | 4 +- .../components/Cell/tests/Cell.test.tsx | 8 ---- 4 files changed, 35 insertions(+), 25 deletions(-) diff --git a/src/components/IndexTable/IndexTable.scss b/src/components/IndexTable/IndexTable.scss index 7b95c1e2f85..351b72e129f 100644 --- a/src/components/IndexTable/IndexTable.scss +++ b/src/components/IndexTable/IndexTable.scss @@ -116,8 +116,7 @@ $loading-panel-height: rem(53px); // stylelint-disable-next-line selector-max-combinators, selector-max-class, selector-max-specificity &, .TableCell-first, - .TableCell-first + .TableCell, - .TableCell-last { + .TableCell-first + .TableCell { background-color: var(--p-surface-primary-selected); } } @@ -135,8 +134,7 @@ $loading-panel-height: rem(53px); // stylelint-disable-next-line selector-max-class, selector-max-combinators, selector-max-specificity &, .TableCell-first, - .TableCell-first + .TableCell, - .TableCell-last { + .TableCell-first + .TableCell { background-color: var(--p-surface-selected-hovered); } } @@ -147,8 +145,7 @@ $loading-panel-height: rem(53px); .TableHeading-first, .TableHeading-second, .TableCell-first, - .TableCell-first + .TableCell, - .TableCell-last { + .TableCell-first + .TableCell { background-color: var(--p-surface-selected); } } @@ -190,11 +187,6 @@ $loading-panel-height: rem(53px); } } -.TableHeading-last { - position: sticky; - right: 0; -} - .TableCell { z-index: z-index(cell, $index-table-stacking-order); text-align: left; @@ -225,13 +217,36 @@ $loading-panel-height: rem(53px); } } -.TableCell-last { +.Table-sticky-last .TableCell:last-child, +.Table-sticky-last .TableHeading-last { @include breakpoint-after($breakpoint-small) { position: sticky; right: 0; - z-index: z-index(sticky-cell, $index-table-stacking-order); - box-shadow: rem(-1px) rem(-1px) 0 0 var(--p-divider, color('sky')); background-color: var(--p-surface, color('white')); + z-index: z-index(sticky-cell, $index-table-stacking-order); + outline: rem(1px) solid var(--p-divider, color('sky')); + } +} + +.Table-sticky-last { + // stylelint-disable-next-line selector-max-class, selector-max-combinators, selector-max-specificity + .statusSuccess .TableCell:last-child { + background-color: var(--p-surface-primary-selected); + } + + // stylelint-disable-next-line selector-max-class, selector-max-combinators, selector-max-specificity + .statusSubdued .TableCell:last-child { + background-color: var(--p-surface-subdued); + } + + // stylelint-disable-next-line selector-max-class, selector-max-combinators, selector-max-specificity + .TableRow-hovered .TableCell:last-child { + background-color: var(--p-surface-selected-hovered); + } + + // stylelint-disable-next-line selector-max-class, selector-max-combinators, selector-max-specificity + .TableRow-selected .TableCell:last-child { + background-color: var(--p-surface-selected); } } diff --git a/src/components/IndexTable/IndexTable.tsx b/src/components/IndexTable/IndexTable.tsx index 7f7565d592c..4984f0fca98 100644 --- a/src/components/IndexTable/IndexTable.tsx +++ b/src/components/IndexTable/IndexTable.tsx @@ -45,6 +45,7 @@ export interface IndexTableBaseProps { children?: React.ReactNode; emptyState?: React.ReactNode; sort?: React.ReactNode; + lastColumnSticky?: boolean; } export interface TableHeadingRect { @@ -64,6 +65,7 @@ function IndexTableBase({ children, emptyState, sort, + lastColumnSticky = false, }: IndexTableBaseProps) { const { loading, @@ -500,6 +502,7 @@ function IndexTableBase({ hasMoreLeftColumns && styles['Table-scrolling'], selectMode && styles.disableTextSelection, selectMode && shouldShowBulkActions && styles.selectMode, + lastColumnSticky && styles['Table-sticky-last'], ); const emptyStateMarkup = emptyState ? ( @@ -566,9 +569,11 @@ function IndexTableBase({ function renderHeading(heading: IndexTableHeading, index: number) { const isSecond = index === 0; + const isLast = index === headings.length - 1; const headingContentClassName = classNames( styles.TableHeading, isSecond && styles['TableHeading-second'], + isLast && !heading.hidden && styles['TableHeading-last'], ); const stickyPositioningStyle = diff --git a/src/components/IndexTable/components/Cell/Cell.tsx b/src/components/IndexTable/components/Cell/Cell.tsx index 427884c362c..0a1d0a85ef5 100644 --- a/src/components/IndexTable/components/Cell/Cell.tsx +++ b/src/components/IndexTable/components/Cell/Cell.tsx @@ -6,14 +6,12 @@ import styles from '../../IndexTable.scss'; export interface CellProps { children?: ReactNode; flush?: boolean; - last?: boolean; } -export const Cell = memo(function Cell({children, flush, last}: CellProps) { +export const Cell = memo(function Cell({children, flush}: CellProps) { const cellClassName = classNames( styles.TableCell, flush && styles['TableCell-flush'], - last && styles['TableCell-last'], ); return {children}; diff --git a/src/components/IndexTable/components/Cell/tests/Cell.test.tsx b/src/components/IndexTable/components/Cell/tests/Cell.test.tsx index 51dfc72f7b0..7d55a1c919a 100644 --- a/src/components/IndexTable/components/Cell/tests/Cell.test.tsx +++ b/src/components/IndexTable/components/Cell/tests/Cell.test.tsx @@ -17,14 +17,6 @@ describe('', () => { className: 'TableCell TableCell-flush', }); }); - - it('applies last column styles when last prop is true', () => { - const cell = mountWithTable(); - - expect(cell).toContainReactComponent('td', { - className: 'TableCell TableCell-last', - }); - }); }); function mountWithTable(children: ReactElement) { From d9d09bb4b45d753f8873ac355075558293a28ed1 Mon Sep 17 00:00:00 2001 From: Pamela Hicks Date: Mon, 28 Jun 2021 20:12:45 -0400 Subject: [PATCH 03/12] Replace box-shadow on sticky cells --- src/components/IndexTable/IndexTable.scss | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/components/IndexTable/IndexTable.scss b/src/components/IndexTable/IndexTable.scss index 351b72e129f..61168132d8a 100644 --- a/src/components/IndexTable/IndexTable.scss +++ b/src/components/IndexTable/IndexTable.scss @@ -2,7 +2,7 @@ $index-table-stacking-order: ( cell: 1, - sticky-cell: 30, + sticky-cell: 31, scroll-bar: 35, bulk-actions: 36, loading-panel: 37, @@ -93,17 +93,14 @@ $loading-panel-height: rem(53px); .TableCell-first, .TableHeading-first { - box-shadow: rem(1px) rem(-1px) 0 0 var(--p-divider); - @include breakpoint-after($breakpoint-small) { - box-shadow: 0 rem(-1px) 0 0 var(--p-divider); - } + filter: drop-shadow(rem(1px) 0 0 var(--p-divider)); } // stylelint-disable-next-line selector-max-class, selector-max-combinators .TableCell-first + .TableCell, .TableHeading-second { @include breakpoint-after($breakpoint-small) { - box-shadow: rem(1px) rem(-1px) 0 0 var(--p-divider); + filter: drop-shadow(rem(1px) 0 0 var(--p-divider)); } } } @@ -111,6 +108,7 @@ $loading-panel-height: rem(53px); .TableRow { background-color: var(--p-surface); cursor: pointer; + filter: drop-shadow(0 rem(-1px) 0 var(--p-divider)); &.statusSuccess { // stylelint-disable-next-line selector-max-combinators, selector-max-class, selector-max-specificity @@ -192,7 +190,6 @@ $loading-panel-height: rem(53px); text-align: left; padding: spacing(tight) spacing(); white-space: nowrap; - box-shadow: 0 rem(-1px) 0 0 var(--p-divider); } .TableCell-flush { @@ -222,9 +219,15 @@ $loading-panel-height: rem(53px); @include breakpoint-after($breakpoint-small) { position: sticky; right: 0; - background-color: var(--p-surface, color('white')); + background-color: var(--p-surface); z-index: z-index(sticky-cell, $index-table-stacking-order); - outline: rem(1px) solid var(--p-divider, color('sky')); + filter: drop-shadow(rem(-1px) 0 0 var(--p-divider)); + } +} + +.Table-sticky-last .TableHeading-last { + @include breakpoint-after($breakpoint-small) { + z-index: auto; } } From 490a95944a504719f329cff1321d9608ea2cbefd Mon Sep 17 00:00:00 2001 From: Pamela Hicks Date: Wed, 30 Jun 2021 16:53:44 -0400 Subject: [PATCH 04/12] Remove sticky left border when scrolled right --- src/components/IndexTable/IndexTable.scss | 7 +++++++ src/components/IndexTable/IndexTable.tsx | 8 ++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/components/IndexTable/IndexTable.scss b/src/components/IndexTable/IndexTable.scss index 61168132d8a..a567cef6b91 100644 --- a/src/components/IndexTable/IndexTable.scss +++ b/src/components/IndexTable/IndexTable.scss @@ -231,6 +231,13 @@ $loading-panel-height: rem(53px); } } +.Table-sticky-scrolled .TableCell:last-child, +.Table-sticky-scrolled .TableHeading-last { + @include breakpoint-after($breakpoint-small) { + filter: none; + } +} + .Table-sticky-last { // stylelint-disable-next-line selector-max-class, selector-max-combinators, selector-max-specificity .statusSuccess .TableCell:last-child { diff --git a/src/components/IndexTable/IndexTable.tsx b/src/components/IndexTable/IndexTable.tsx index 4984f0fca98..f78d8989ec1 100644 --- a/src/components/IndexTable/IndexTable.tsx +++ b/src/components/IndexTable/IndexTable.tsx @@ -87,7 +87,6 @@ function IndexTableBase({ toggle: toggleHasMoreLeftColumns, } = useToggle(false); - const onboardingScrollButtons = useRef(false); const tablePosition = useRef({top: 0, left: 0}); const tableHeadingRects = useRef([]); @@ -217,6 +216,8 @@ function IndexTableBase({ debounceResizeTableScrollbar(); }, [debounceResizeTableScrollbar, resizeTableHeadings]); + const [canScrollRight, setCanScrollRight] = useState(true); + const handleScrollContainerScroll = useCallback( (canScrollLeft, canScrollRight) => { if (!scrollableContainerElement.current || !scrollBarElement.current) { @@ -242,9 +243,7 @@ function IndexTableBase({ toggleHasMoreLeftColumns(); } - if (!canScrollRight) { - onboardingScrollButtons.current = false; - } + setCanScrollRight(canScrollRight); }, [hasMoreLeftColumns, toggleHasMoreLeftColumns], ); @@ -503,6 +502,7 @@ function IndexTableBase({ selectMode && styles.disableTextSelection, selectMode && shouldShowBulkActions && styles.selectMode, lastColumnSticky && styles['Table-sticky-last'], + lastColumnSticky && !canScrollRight && styles['Table-sticky-scrolled'], ); const emptyStateMarkup = emptyState ? ( From f1fefc4bb762f4a8b7862b4f5eea9c3c69759d54 Mon Sep 17 00:00:00 2001 From: Pamela Hicks Date: Wed, 30 Jun 2021 18:16:12 -0400 Subject: [PATCH 05/12] Add tests --- .../IndexTable/tests/IndexTable.test.tsx | 81 ++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-) diff --git a/src/components/IndexTable/tests/IndexTable.test.tsx b/src/components/IndexTable/tests/IndexTable.test.tsx index 62a8147725e..1a6768a3e40 100644 --- a/src/components/IndexTable/tests/IndexTable.test.tsx +++ b/src/components/IndexTable/tests/IndexTable.test.tsx @@ -148,6 +148,18 @@ describe('', () => { }); }); + it('applies sticky last column styles when `lastColumnSticky` prop is true', () => { + const index = mountWithApp( + + {mockTableItems.map(mockRenderRow)} + , + ); + + expect(index).toContainReactComponent('table', { + className: 'Table Table-sticky-last', + }); + }); + describe('ScrollContainer', () => { it('updates sticky header scroll left on scoll', () => { const updatedScrollLeft = 25; @@ -172,7 +184,7 @@ describe('', () => { expect(stickyHeaderElementScrollLeft).toBe(updatedScrollLeft); }); - it('updates stickty table column header styles when scrolling right & hasMoreLeftColumns is false', () => { + it('updates sticky table column header styles when scrolling right & hasMoreLeftColumns is false', () => { const index = mountWithApp( {mockTableItems.map(mockRenderRow)} @@ -187,6 +199,22 @@ describe('', () => { 'StickyTableColumnHeader StickyTableColumnHeader-isScrolling', }); }); + + it('updates sticky last column styles when scrolled right', () => { + const index = mountWithApp( + + {mockTableItems.map(mockRenderRow)} + , + ); + + const scrollContainer = index.find(ScrollContainer); + scrollContainer!.trigger('onScroll', true, false); + + expect(index).toContainReactComponent('table', { + className: + 'Table Table-scrolling Table-sticky-last Table-sticky-scrolled', + }); + }); }); describe('resize', function () { @@ -276,6 +304,57 @@ describe('', () => { expect(index).toContainReactComponent(VisuallyHidden, {children: title}); }); + + it('renders a sticky last heading if `lastColumnSticky` prop is true and last heading is not hidden', () => { + const title = 'Heading two'; + const headings: IndexTableProps['headings'] = [ + {title: 'Heading one'}, + {title, hidden: false}, + ]; + const index = mountWithApp( + + {mockTableItems.map(mockRenderRow)} + , + ); + + expect(index).toContainReactComponent('table', { + className: 'Table Table-sticky-last', + }); + expect(index).toContainReactComponent('th', { + children: title, + className: 'TableHeading TableHeading-last', + }); + }); + + it('does not render a sticky last heading if `lastColumnSticky` prop is true and last heading is hidden', () => { + const title = 'Heading two'; + const headings: IndexTableProps['headings'] = [ + {title: 'Heading one'}, + {title, hidden: true}, + ]; + const index = mountWithApp( + + {mockTableItems.map(mockRenderRow)} + , + ); + + expect(index).toContainReactComponent('table', { + className: 'Table Table-sticky-last', + }); + expect(index).toContainReactComponent(VisuallyHidden, { + children: title, + }); + }); }); describe('BulkActions', () => { From 64ab18dd796415d7a50f7d64a6b8b8baf1b59530 Mon Sep 17 00:00:00 2001 From: Pamela Hicks Date: Mon, 28 Jun 2021 20:15:33 -0400 Subject: [PATCH 06/12] Fix unreleased list --- UNRELEASED.md | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/UNRELEASED.md b/UNRELEASED.md index 289530fd2e3..3a715cb9dd9 100644 --- a/UNRELEASED.md +++ b/UNRELEASED.md @@ -16,21 +16,18 @@ Use [the changelog guidelines](https://git.io/polaris-changelog-guidelines) to f - Rename and expose Card compound components types ([#4261](https://github.com/Shopify/polaris-react/pull/4261)) - Add `monospaced` prop to `TextField` component ([#4264](https://github.com/Shopify/polaris-react/pull/4264)) - Add base tight spacing option to `Stack` component([#4273](https://github.com/Shopify/polaris-react/pull/4273)) -- Add `variableHeight` prop to `DropZone` so children control its height ([#4136](https://github.com/Shopify/polaris-react/pull/4136)) -- Add print styles to `Card`, `Heading`, `Layout`, `Layout.Section`, `Subheading`, `TextStyle` components ([#4142](https://github.com/Shopify/polaris-react/pull/4142)) -- Add `fullWidth` prop to `ColorPicker` so the color picker can take the full width ([#4152](https://github.com/Shopify/polaris-react/pull/4152)) -- Add `noScroll` prop to `Modal` which prevents modal contents from scrolling ([#4153](https://github.com/Shopify/polaris-react/pull/4153)) -- Added new `color` prop to ProgressBar ([#3415](https://github.com/Shopify/polaris-react/pull/3415)) -- Added `requiredIndicator` prop to `Label`, `Labelled`, `Select` and `TextField` ([#4119](https://github.com/Shopify/polaris-react/pull/4119)) -- Add `small` prop to `Modal` so that width can be decreased to 380px ([#4177](https://github.com/Shopify/polaris-react/pull/4177)) -- Add `status` prop to `IndexTable.Row` to allow table rows to specify background colors([#4146](https://github.com/Shopify/polaris-react/pull/4146)) -- Disabled `pointer-events` on the prefix and suffix elements of the `TextField` component ([#4207](https://github.com/Shopify/polaris-react/pull/4207)) -- Add `last` prop to `IndexTable.Cell` to create a sticky last cell on viewports larger than small ([#4150](https://github.com/Shopify/polaris-react/pull/4150)) +- Add `lastColumnSticky` prop to `IndexTable` to create a sticky last cell and optional sticky last heading on viewports larger than small ([#4150](https://github.com/Shopify/polaris-react/pull/4150)) ### Bug fixes - Fixed a bug in `Banner` where loading state wasn't getting passed to `primaryAction` ([#4338](https://github.com/Shopify/polaris-react/pull/4338)) - Fixed a bug `TextField` where Safari would render the incorrect text color ([#4344](https://github.com/Shopify/polaris-react/pull/4344)) +- Fix bug in Safari where `Button` text is gray instead of white after changing state from disabled to enabled ([#4270](https://github.com/Shopify/polaris-react/pull/4270)) +- Fix console warnings when `DataTable` unmounts ([#4249](https://github.com/Shopify/polaris-react/pull/4249)) +- Fix console warnings displaying multiple times in `Sheet` ([#4269](https://github.com/Shopify/polaris-react/pull/4269)) +- Remove top shadow when `Popover` and `Scrollable` scroll hinting is complete ([#4265](https://github.com/Shopify/polaris-react/pull/4265)) +- Bring back borders on the `IndexTable` sticky cells ([#4150](https://github.com/Shopify/polaris-react/pull/4150)) +- Adjust `IndexTable` sticky z-index to avoid collisions with focused `TextField` ([#4150](https://github.com/Shopify/polaris-react/pull/4150)) ### Documentation From 6ed263494c645e3a05d2821ab95c43ad1fe78cb4 Mon Sep 17 00:00:00 2001 From: Pamela Hicks Date: Wed, 30 Jun 2021 18:16:41 -0400 Subject: [PATCH 07/12] Update readme --- src/components/IndexTable/README.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/components/IndexTable/README.md b/src/components/IndexTable/README.md index 172262a994b..f75e7a0ecc0 100644 --- a/src/components/IndexTable/README.md +++ b/src/components/IndexTable/README.md @@ -710,7 +710,7 @@ function IndexTableWithFilteringExample() { An index table with rows differentiated by status. ```jsx -function SimpleIndexTableExample() { +function IndexTableWithRowStatusExample() { const customers = [ { id: '3411', @@ -786,10 +786,10 @@ function SimpleIndexTableExample() { ### Index table with sticky last column -An index table with a sticky last column that stays visible on scroll. +An index table with a sticky last column that stays visible on scroll. The last heading will also be sticky if not hidden. ```jsx -function SimpleIndexTableExample() { +function StickyLastCellIndexTableExample() { const customers = [ { id: '3411', @@ -832,7 +832,7 @@ function SimpleIndexTableExample() { {location} {orders} - {amountSpent} + {amountSpent} ), ); @@ -850,8 +850,9 @@ function SimpleIndexTableExample() { {title: 'Name'}, {title: 'Location'}, {title: 'Order count'}, - {title: 'Amount spent'}, + {title: 'Amount spent', hidden: false}, ]} + lastColumnSticky > {rowMarkup} @@ -1014,11 +1015,12 @@ function IndexTableWithAllElementsExample() { hasMoreItems bulkActions={bulkActions} promotedBulkActions={promotedBulkActions} + lastColumnSticky headings={[ {title: 'Name'}, {title: 'Location'}, {title: 'Order count'}, - {title: 'Amount spent'}, + {title: 'Amount spent', hidden: false}, ]} > {rowMarkup} @@ -1358,7 +1360,6 @@ An `IndexTableCell` is used to render a single cell within an `IndexTableRow` | Prop | Type | Description | | ----- | ------- | -------------------------------------------------------------------------------- | | flush | boolean | A boolean property indicating whether the cell should remove the default padding | -| last | boolean | A boolean property indicating whether the last cell should stay sticky | --- From e03f42d1e3079125a0a75feda9754825e52d0409 Mon Sep 17 00:00:00 2001 From: Pamela Hicks Date: Fri, 2 Jul 2021 14:13:10 -0400 Subject: [PATCH 08/12] Initialize canScrollRight on load --- src/components/IndexTable/IndexTable.scss | 7 ++--- src/components/IndexTable/IndexTable.tsx | 28 ++++++++++++++++--- .../IndexTable/tests/IndexTable.test.tsx | 3 +- 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/src/components/IndexTable/IndexTable.scss b/src/components/IndexTable/IndexTable.scss index a567cef6b91..7517d2ba568 100644 --- a/src/components/IndexTable/IndexTable.scss +++ b/src/components/IndexTable/IndexTable.scss @@ -221,7 +221,6 @@ $loading-panel-height: rem(53px); right: 0; background-color: var(--p-surface); z-index: z-index(sticky-cell, $index-table-stacking-order); - filter: drop-shadow(rem(-1px) 0 0 var(--p-divider)); } } @@ -231,10 +230,10 @@ $loading-panel-height: rem(53px); } } -.Table-sticky-scrolled .TableCell:last-child, -.Table-sticky-scrolled .TableHeading-last { +.Table-sticky-scrolling .TableCell:last-child, +.Table-sticky-scrolling .TableHeading-last { @include breakpoint-after($breakpoint-small) { - filter: none; + filter: drop-shadow(rem(-1px) 0 0 var(--p-divider)); } } diff --git a/src/components/IndexTable/IndexTable.tsx b/src/components/IndexTable/IndexTable.tsx index f78d8989ec1..534f1eacb9d 100644 --- a/src/components/IndexTable/IndexTable.tsx +++ b/src/components/IndexTable/IndexTable.tsx @@ -205,6 +205,27 @@ function IndexTableBase({ [resizeTableScrollBar], ); + const [canScrollRight, setCanScrollRight] = useState(true); + + const setRightScroll = useCallback(() => { + if ( + !lastColumnSticky || + !tableElement.current || + !scrollableContainerElement.current + ) { + return; + } + + const tableRect = tableElement.current.getBoundingClientRect(); + const scrollableRect = scrollableContainerElement.current.getBoundingClientRect(); + + setCanScrollRight(tableRect.width > scrollableRect.width); + }, [lastColumnSticky, setCanScrollRight]); + + useEffect(() => { + setRightScroll(); + }, [setRightScroll]); + const handleResize = useCallback(() => { // hide the scrollbar when resizing scrollBarElement.current?.style.setProperty( @@ -214,9 +235,8 @@ function IndexTableBase({ resizeTableHeadings(); debounceResizeTableScrollbar(); - }, [debounceResizeTableScrollbar, resizeTableHeadings]); - - const [canScrollRight, setCanScrollRight] = useState(true); + setRightScroll(); + }, [debounceResizeTableScrollbar, resizeTableHeadings, setRightScroll]); const handleScrollContainerScroll = useCallback( (canScrollLeft, canScrollRight) => { @@ -502,7 +522,7 @@ function IndexTableBase({ selectMode && styles.disableTextSelection, selectMode && shouldShowBulkActions && styles.selectMode, lastColumnSticky && styles['Table-sticky-last'], - lastColumnSticky && !canScrollRight && styles['Table-sticky-scrolled'], + lastColumnSticky && canScrollRight && styles['Table-sticky-scrolling'], ); const emptyStateMarkup = emptyState ? ( diff --git a/src/components/IndexTable/tests/IndexTable.test.tsx b/src/components/IndexTable/tests/IndexTable.test.tsx index 1a6768a3e40..3e1c5f6188a 100644 --- a/src/components/IndexTable/tests/IndexTable.test.tsx +++ b/src/components/IndexTable/tests/IndexTable.test.tsx @@ -211,8 +211,7 @@ describe('', () => { scrollContainer!.trigger('onScroll', true, false); expect(index).toContainReactComponent('table', { - className: - 'Table Table-scrolling Table-sticky-last Table-sticky-scrolled', + className: 'Table Table-scrolling Table-sticky-last', }); }); }); From 981280ac051d4728206eb875abb390e67c24c5b6 Mon Sep 17 00:00:00 2001 From: Pamela Hicks Date: Fri, 2 Jul 2021 16:21:19 -0400 Subject: [PATCH 09/12] Adjust styles for condensed --- src/components/IndexTable/IndexTable.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/IndexTable/IndexTable.scss b/src/components/IndexTable/IndexTable.scss index 7517d2ba568..a48e82b6e78 100644 --- a/src/components/IndexTable/IndexTable.scss +++ b/src/components/IndexTable/IndexTable.scss @@ -409,6 +409,7 @@ $scroll-bar-border-radius: rem(4px); transition: transform easing() duration(); display: flex; border-top: border('divider'); + filter: none; } [data-selectmode='true'] { @@ -432,7 +433,6 @@ $scroll-bar-border-radius: rem(4px); min-height: 5.6rem; padding: 1rem spacing(); background-color: var(--p-surface); - box-shadow: shadow(); } .StickyTable-condensed { From 5207a080052fc12b7c14abf8cc1121eaeb52e2df Mon Sep 17 00:00:00 2001 From: Pamela Hicks Date: Tue, 3 Aug 2021 17:05:37 -0400 Subject: [PATCH 10/12] Update callback name and deps list per review comment --- src/components/IndexTable/IndexTable.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/IndexTable/IndexTable.tsx b/src/components/IndexTable/IndexTable.tsx index 534f1eacb9d..e38b2e98c26 100644 --- a/src/components/IndexTable/IndexTable.tsx +++ b/src/components/IndexTable/IndexTable.tsx @@ -207,7 +207,7 @@ function IndexTableBase({ const [canScrollRight, setCanScrollRight] = useState(true); - const setRightScroll = useCallback(() => { + const handleCanScrollRight = useCallback(() => { if ( !lastColumnSticky || !tableElement.current || @@ -220,11 +220,11 @@ function IndexTableBase({ const scrollableRect = scrollableContainerElement.current.getBoundingClientRect(); setCanScrollRight(tableRect.width > scrollableRect.width); - }, [lastColumnSticky, setCanScrollRight]); + }, [lastColumnSticky]); useEffect(() => { - setRightScroll(); - }, [setRightScroll]); + handleCanScrollRight(); + }, [handleCanScrollRight]); const handleResize = useCallback(() => { // hide the scrollbar when resizing @@ -235,8 +235,8 @@ function IndexTableBase({ resizeTableHeadings(); debounceResizeTableScrollbar(); - setRightScroll(); - }, [debounceResizeTableScrollbar, resizeTableHeadings, setRightScroll]); + handleCanScrollRight(); + }, [debounceResizeTableScrollbar, resizeTableHeadings, handleCanScrollRight]); const handleScrollContainerScroll = useCallback( (canScrollLeft, canScrollRight) => { From 1adbcf4153493c958a0fe9aa5618f7eaf8699d95 Mon Sep 17 00:00:00 2001 From: Pamela Hicks Date: Tue, 3 Aug 2021 18:03:56 -0400 Subject: [PATCH 11/12] Refactor styles per review comment --- src/components/IndexTable/IndexTable.scss | 68 +++++++++++++---------- 1 file changed, 39 insertions(+), 29 deletions(-) diff --git a/src/components/IndexTable/IndexTable.scss b/src/components/IndexTable/IndexTable.scss index a48e82b6e78..cf1800a0264 100644 --- a/src/components/IndexTable/IndexTable.scss +++ b/src/components/IndexTable/IndexTable.scss @@ -214,49 +214,59 @@ $loading-panel-height: rem(53px); } } -.Table-sticky-last .TableCell:last-child, -.Table-sticky-last .TableHeading-last { - @include breakpoint-after($breakpoint-small) { - position: sticky; - right: 0; - background-color: var(--p-surface); - z-index: z-index(sticky-cell, $index-table-stacking-order); +.Table-sticky-scrolling { + .TableCell:last-child, + .TableHeading-last { + @include breakpoint-after($breakpoint-small) { + filter: drop-shadow(rem(-1px) 0 0 var(--p-divider)); + } } } -.Table-sticky-last .TableHeading-last { - @include breakpoint-after($breakpoint-small) { - z-index: auto; +.Table-sticky-last { + .TableCell:last-child { + @include breakpoint-after($breakpoint-small) { + position: sticky; + right: 0; + background-color: var(--p-surface); + z-index: z-index(sticky-cell, $index-table-stacking-order); + } } -} -.Table-sticky-scrolling .TableCell:last-child, -.Table-sticky-scrolling .TableHeading-last { - @include breakpoint-after($breakpoint-small) { - filter: drop-shadow(rem(-1px) 0 0 var(--p-divider)); + .TableHeading-last { + @include breakpoint-after($breakpoint-small) { + position: sticky; + right: 0; + background-color: var(--p-surface); + z-index: auto; + } } -} -.Table-sticky-last { - // stylelint-disable-next-line selector-max-class, selector-max-combinators, selector-max-specificity - .statusSuccess .TableCell:last-child { - background-color: var(--p-surface-primary-selected); + // stylelint-disable selector-max-class, selector-max-combinators, selector-max-specificity + .statusSuccess { + .TableCell:last-child { + background-color: var(--p-surface-primary-selected); + } } - // stylelint-disable-next-line selector-max-class, selector-max-combinators, selector-max-specificity - .statusSubdued .TableCell:last-child { - background-color: var(--p-surface-subdued); + .statusSubdued { + .TableCell:last-child { + background-color: var(--p-surface-subdued); + } } - // stylelint-disable-next-line selector-max-class, selector-max-combinators, selector-max-specificity - .TableRow-hovered .TableCell:last-child { - background-color: var(--p-surface-selected-hovered); + .TableRow-hovered { + .TableCell:last-child { + background-color: var(--p-surface-selected-hovered); + } } - // stylelint-disable-next-line selector-max-class, selector-max-combinators, selector-max-specificity - .TableRow-selected .TableCell:last-child { - background-color: var(--p-surface-selected); + .TableRow-selected { + .TableCell:last-child { + background-color: var(--p-surface-selected); + } } + // stylelint-enable selector-max-class, selector-max-combinators, selector-max-specificity } .StickyTable { From 4da68012fc113ec4f52ad3cd7ce231f0d4bac531 Mon Sep 17 00:00:00 2001 From: Pamela Hicks Date: Tue, 3 Aug 2021 18:08:37 -0400 Subject: [PATCH 12/12] Resolve conflics in UNRELEASED --- UNRELEASED.md | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/UNRELEASED.md b/UNRELEASED.md index 3a715cb9dd9..d5ce9938d8d 100644 --- a/UNRELEASED.md +++ b/UNRELEASED.md @@ -9,13 +9,6 @@ Use [the changelog guidelines](https://git.io/polaris-changelog-guidelines) to f - Added `id` prop to `Layout` and `Heading` for hash linking ([#4307](https://github.com/Shopify/polaris-react/pull/4307)) - Added `external` prop to `Navigation.Item` component ([#4310](https://github.com/Shopify/polaris-react/pull/4310)) - Added `ariaLabelledBy` props to `Navigation` component to allow a hidden label for accessibility ([#4343](https://github.com/Shopify/polaris-react/pull/4343)) -- Prevented `KeypressListener` attaching/detaching on every render ([#4173](https://github.com/Shopify/polaris-react/pull/4173)) -- Added `animated` prop in `ProgressBar` ([#4251](https://github.com/Shopify/polaris-react/pull/4251)) -- Added `divider` prop to `Page` component ([#4260](https://github.com/Shopify/polaris-react/pull/4260)) -- Add `activator` prop to `Sheet` so the triggering element will regain focus ([#4201](https://github.com/Shopify/polaris-react/pull/4201)) -- Rename and expose Card compound components types ([#4261](https://github.com/Shopify/polaris-react/pull/4261)) -- Add `monospaced` prop to `TextField` component ([#4264](https://github.com/Shopify/polaris-react/pull/4264)) -- Add base tight spacing option to `Stack` component([#4273](https://github.com/Shopify/polaris-react/pull/4273)) - Add `lastColumnSticky` prop to `IndexTable` to create a sticky last cell and optional sticky last heading on viewports larger than small ([#4150](https://github.com/Shopify/polaris-react/pull/4150)) ### Bug fixes @@ -23,9 +16,6 @@ Use [the changelog guidelines](https://git.io/polaris-changelog-guidelines) to f - Fixed a bug in `Banner` where loading state wasn't getting passed to `primaryAction` ([#4338](https://github.com/Shopify/polaris-react/pull/4338)) - Fixed a bug `TextField` where Safari would render the incorrect text color ([#4344](https://github.com/Shopify/polaris-react/pull/4344)) - Fix bug in Safari where `Button` text is gray instead of white after changing state from disabled to enabled ([#4270](https://github.com/Shopify/polaris-react/pull/4270)) -- Fix console warnings when `DataTable` unmounts ([#4249](https://github.com/Shopify/polaris-react/pull/4249)) -- Fix console warnings displaying multiple times in `Sheet` ([#4269](https://github.com/Shopify/polaris-react/pull/4269)) -- Remove top shadow when `Popover` and `Scrollable` scroll hinting is complete ([#4265](https://github.com/Shopify/polaris-react/pull/4265)) - Bring back borders on the `IndexTable` sticky cells ([#4150](https://github.com/Shopify/polaris-react/pull/4150)) - Adjust `IndexTable` sticky z-index to avoid collisions with focused `TextField` ([#4150](https://github.com/Shopify/polaris-react/pull/4150))