Skip to content

Commit f714012

Browse files
authored
[IndexTable] Add sort toggle labels and fix z-index icon issue (#7360)
### WHY are these changes introduced? Fixes Shopify/web#74406 Fixes Shopify/web#74393 This PR fixes a couple of bugs in the IndexTable when the table is sortable and adds the ability to have Tooltips showing the sort direction label. - Fixes a visual bug where if a table is sticky and sortable, the sticky headings have a different color to the unsticky ones - Fixes a visual bug where the sort icon would display above the sticky heading cells - Adds functionality to display the label of the sort direction in a Tooltip when hovering over the index table heading. https://user-images.githubusercontent.com/2562596/194280147-f553b94e-6f91-411c-9914-87bb96c35103.mov ### 🎩 checklist - [x] Tested on [mobile](https://github.com/Shopify/polaris/blob/main/documentation/Tophatting.md#cross-browser-testing) - [x] Tested on [multiple browsers](https://help.shopify.com/en/manual/shopify-admin/supported-browsers) - [x] Tested for [accessibility](https://github.com/Shopify/polaris/blob/main/documentation/Accessibility%20testing.md) - [x] Updated the component's `README.md` with documentation changes - [x] [Tophatted documentation](https://github.com/Shopify/polaris/blob/main/documentation/Tophatting%20documentation.md) changes in the style guide
1 parent 5d0a18f commit f714012

File tree

5 files changed

+168
-21
lines changed

5 files changed

+168
-21
lines changed

.changeset/cyan-adults-refuse.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@shopify/polaris': minor
3+
---
4+
5+
Update `IndexTable` in sortable mode to fix visual bugs and include label Tooltips

polaris-react/src/components/IndexTable/IndexTable.scss

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,11 +213,12 @@ $loading-panel-height: 53px;
213213
}
214214

215215
.TableHeadingSortButton {
216+
position: static;
216217
background: none;
217218
padding: 0;
218219
border: 0;
219220
cursor: pointer;
220-
display: flex;
221+
display: inline-flex;
221222
align-items: center;
222223
justify-content: center;
223224
font-weight: var(--p-font-weight-medium);
@@ -235,13 +236,23 @@ $loading-panel-height: 53px;
235236
.TableHeadingSortIcon {
236237
order: 1;
237238
opacity: 0;
238-
transition: var(--p-ease) var(--p-duration-150) opacity;
239+
height: var(--p-space-5);
240+
width: var(--p-space-5);
241+
transition: opacity var(--p-duration-200) var(--p-ease-in)
242+
var(--p-duration-100);
239243
}
240244

241245
.TableHeadingSortIcon-visible {
242246
opacity: 1;
243247
}
244248

249+
.TableHeadingSortSvg {
250+
display: block;
251+
width: 100%;
252+
max-width: 100%;
253+
max-height: 100%;
254+
}
255+
245256
.ColumnHeaderCheckboxWrapper {
246257
display: flex;
247258
}
@@ -390,6 +401,12 @@ $loading-panel-height: 53px;
390401
}
391402
}
392403

404+
.Table-sortable {
405+
.TableHeading {
406+
background-color: var(--p-surface-subdued);
407+
}
408+
}
409+
393410
.StickyTable {
394411
position: relative;
395412
top: 0;

polaris-react/src/components/IndexTable/IndexTable.stories.tsx

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1351,38 +1351,65 @@ export function WithSortableHeadings() {
13511351
const [sortIndex, setSortIndex] = useState(0);
13521352
const [sortDirection, setSortDirection] = useState('descending');
13531353

1354+
const sortToggleLabels = {
1355+
0: {ascending: 'A-Z', descending: 'Z-A'},
1356+
1: {ascending: 'Ascending', descending: 'Descending'},
1357+
2: {ascending: 'Newest', descending: 'Oldest'},
1358+
3: {ascending: 'Ascending', descending: 'Ascending'},
1359+
4: {ascending: 'A-Z', descending: 'Z-A'},
1360+
5: {ascending: 'A-Z', descending: 'Z-A'},
1361+
6: {ascending: 'A-Z', descending: 'Z-A'},
1362+
7: {ascending: 'A-Z', descending: 'Z-A'},
1363+
};
1364+
13541365
const initialRows = [
13551366
{
13561367
id: '3411',
13571368
url: 'customers/341',
13581369
name: 'Mae Jemison',
1370+
date: '2022-02-04',
13591371
location: 'Decatur, USA',
13601372
orders: 20,
13611373
amountSpent: '$2,400',
1374+
fulfillmentStatus: 'Fulfilled',
1375+
paymentStatus: 'Paid',
1376+
notes: '',
13621377
},
13631378
{
13641379
id: '2561',
13651380
url: 'customers/256',
1381+
date: '2022-01-19',
13661382
name: 'Ellen Ochoa',
13671383
location: 'Los Angeles, USA',
13681384
orders: 30,
13691385
amountSpent: '$140',
1386+
fulfillmentStatus: 'Fulfilled',
1387+
paymentStatus: 'Not paid',
1388+
notes: 'This customer lives on the 3rd floor',
13701389
},
13711390
{
13721391
id: '1245',
13731392
url: 'customers/123',
1393+
date: '2021-12-12',
13741394
name: 'Anne-Marie Johnson',
13751395
location: 'Portland, USA',
13761396
orders: 10,
13771397
amountSpent: '$250',
1398+
fulfillmentStatus: 'Fulfilled',
1399+
paymentStatus: 'Not paid',
1400+
notes: '',
13781401
},
13791402
{
13801403
id: '8741',
13811404
url: 'customers/543',
1405+
date: '2022-05-11',
13821406
name: 'Bradley Stevens',
13831407
location: 'Hialeah, USA',
13841408
orders: 5,
13851409
amountSpent: '$26',
1410+
fulfillmentStatus: 'Unfulfilled',
1411+
paymentStatus: 'Not paid',
1412+
notes: 'This customer has requested fragile delivery',
13861413
},
13871414
];
13881415
const [sortedRows, setSortedRows] = useState(
@@ -1420,7 +1447,20 @@ export function WithSortableHeadings() {
14201447
}
14211448

14221449
const rowMarkup = rows.map(
1423-
({id, name, location, orders, amountSpent}, index) => (
1450+
(
1451+
{
1452+
id,
1453+
name,
1454+
date,
1455+
location,
1456+
orders,
1457+
amountSpent,
1458+
fulfillmentStatus,
1459+
paymentStatus,
1460+
notes,
1461+
},
1462+
index,
1463+
) => (
14241464
<IndexTable.Row
14251465
id={id}
14261466
key={id}
@@ -1430,9 +1470,13 @@ export function WithSortableHeadings() {
14301470
<IndexTable.Cell>
14311471
<TextStyle variation="strong">{name}</TextStyle>
14321472
</IndexTable.Cell>
1473+
<IndexTable.Cell>{date}</IndexTable.Cell>
14331474
<IndexTable.Cell>{orders}</IndexTable.Cell>
14341475
<IndexTable.Cell>{amountSpent}</IndexTable.Cell>
14351476
<IndexTable.Cell>{location}</IndexTable.Cell>
1477+
<IndexTable.Cell>{fulfillmentStatus}</IndexTable.Cell>
1478+
<IndexTable.Cell>{paymentStatus}</IndexTable.Cell>
1479+
<IndexTable.Cell>{notes}</IndexTable.Cell>
14361480
</IndexTable.Row>
14371481
),
14381482
);
@@ -1448,14 +1492,20 @@ export function WithSortableHeadings() {
14481492
onSelectionChange={handleSelectionChange}
14491493
headings={[
14501494
{title: 'Name'},
1495+
{title: 'Date'},
14511496
{title: 'Order count'},
14521497
{title: 'Amount spent'},
14531498
{title: 'Location'},
1499+
{title: 'Fulfillment status'},
1500+
{title: 'Payment status'},
1501+
{title: 'Notes'},
14541502
]}
1455-
sortable={[true, false, false, true]}
1503+
sortable={[true, true, false, true, true, false, false]}
14561504
sortDirection={sortDirection}
14571505
sortColumnIndex={sortIndex}
14581506
onSort={handleClickSortHeading}
1507+
sortToggleLabels={sortToggleLabels}
1508+
lastColumnSticky
14591509
>
14601510
{rowMarkup}
14611511
</IndexTable>

polaris-react/src/components/IndexTable/IndexTable.tsx

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@ import {Checkbox as PolarisCheckbox} from '../Checkbox';
1515
import {EmptySearchResult} from '../EmptySearchResult';
1616
// eslint-disable-next-line import/no-deprecated
1717
import {EventListener} from '../EventListener';
18-
import {Icon} from '../Icon';
1918
import {Stack} from '../Stack';
2019
import {Sticky} from '../Sticky';
2120
import {Spinner} from '../Spinner';
2221
import {VisuallyHidden} from '../VisuallyHidden';
2322
import {Button} from '../Button';
23+
import {Tooltip} from '../Tooltip';
2424
import {UnstyledButton} from '../UnstyledButton';
2525
import {BulkActions, BulkActionsProps} from '../BulkActions';
2626
import {classNames} from '../../utilities/css';
@@ -60,6 +60,14 @@ export type IndexTableHeading =
6060

6161
export type IndexTableSortDirection = 'ascending' | 'descending';
6262

63+
type IndexTableSortToggleLabel = {
64+
[key in IndexTableSortDirection]: string;
65+
};
66+
67+
interface IndexTableSortToggleLabels {
68+
[key: number]: IndexTableSortToggleLabel;
69+
}
70+
6371
export interface IndexTableBaseProps {
6472
headings: NonEmptyArray<IndexTableHeading>;
6573
promotedBulkActions?: BulkActionsProps['promotedActions'];
@@ -85,6 +93,9 @@ export interface IndexTableBaseProps {
8593
sortColumnIndex?: number;
8694
/** Callback fired on click or keypress of a sortable column heading. */
8795
onSort?(headingIndex: number, direction: IndexTableSortDirection): void;
96+
/** Optional dictionary of sort toggle labels for each sortable column, with ascending and descending label,
97+
* with the key as the index of the column */
98+
sortToggleLabels?: IndexTableSortToggleLabels;
8899
}
89100

90101
export interface TableHeadingRect {
@@ -109,6 +120,7 @@ function IndexTableBase({
109120
defaultSortDirection = 'descending',
110121
sortColumnIndex,
111122
onSort,
123+
sortToggleLabels,
112124
...restProps
113125
}: IndexTableBaseProps) {
114126
const {
@@ -655,13 +667,16 @@ function IndexTableBase({
655667
</AfterInitialMount>
656668
) : null;
657669

670+
const isSortable = sortable?.some((value) => value);
671+
658672
const tableClassNames = classNames(
659673
styles.Table,
660674
hasMoreLeftColumns && styles['Table-scrolling'],
661675
selectMode && styles.disableTextSelection,
662676
selectMode && shouldShowBulkActions && styles.selectMode,
663677
!selectable && styles['Table-unselectable'],
664678
canFitStickyColumn && styles['Table-sticky'],
679+
isSortable && styles['Table-sortable'],
665680
canFitStickyColumn && lastColumnSticky && styles['Table-sticky-last'],
666681
canFitStickyColumn &&
667682
lastColumnSticky &&
@@ -830,35 +845,34 @@ function IndexTableBase({
830845
const isCurrentlySorted = index === sortColumnIndex;
831846
const isAscending = sortDirection === 'ascending';
832847
let newDirection: IndexTableSortDirection = defaultSortDirection;
833-
let source =
848+
let SourceComponent =
834849
defaultSortDirection === 'ascending'
835850
? SortAscendingMajor
836851
: SortDescendingMajor;
837852
if (isCurrentlySorted) {
838853
newDirection = isAscending ? 'descending' : 'ascending';
839-
source =
854+
SourceComponent =
840855
sortDirection === 'ascending'
841856
? SortAscendingMajor
842857
: SortDescendingMajor;
843858
}
844859

845-
const sortAccessibilityLabel = i18n.translate(
846-
'Polaris.IndexTable.sortAccessibilityLabel',
847-
{direction: newDirection},
848-
);
849-
850860
const iconMarkup = (
851861
<span
852862
className={classNames(
853863
styles.TableHeadingSortIcon,
854864
isCurrentlySorted && styles['TableHeadingSortIcon-visible'],
855865
)}
856866
>
857-
<Icon source={source} accessibilityLabel={sortAccessibilityLabel} />
867+
<SourceComponent
868+
focusable="false"
869+
aria-hidden="true"
870+
className={styles.TableHeadingSortSvg}
871+
/>
858872
</span>
859873
);
860874

861-
return (
875+
const sortMarkup = (
862876
<UnstyledButton
863877
onClick={() => handleSortHeadingClick(index, newDirection)}
864878
className={styles.TableHeadingSortButton}
@@ -868,6 +882,18 @@ function IndexTableBase({
868882
{headingContent}
869883
</UnstyledButton>
870884
);
885+
886+
if (!sortToggleLabels) {
887+
return sortMarkup;
888+
}
889+
890+
const tooltipDirection = isCurrentlySorted
891+
? sortDirection!
892+
: defaultSortDirection;
893+
894+
const tooltipContent = sortToggleLabels[index][tooltipDirection];
895+
896+
return <Tooltip content={tooltipContent}>{sortMarkup}</Tooltip>;
871897
}
872898
return headingContent;
873899
}

0 commit comments

Comments
 (0)