Scroll to top of the table when navigating table pages (https://github.com/woocommerce/woocommerce-admin/pull/2051)
* Scroll to top of the table when navigating table pages * Cleanup * Avoid using scroll-padding-top * Add space between the table top and the scroll point * Only call if the page is different * Move focus to the top of the table when switching pages * Use CSS variables in the Activity Panel and breadcrumbs CSS (https://github.com/woocommerce/woocommerce-admin/pull/2096) * Use CSS variables in the Activity Panel and breadcrumbs CSS * Cleanup * Focus on table element when navigating pages
This commit is contained in:
parent
40b47c3a18
commit
1c67b40d76
|
@ -3,8 +3,9 @@
|
|||
* External dependencies
|
||||
*/
|
||||
import { applyFilters } from '@wordpress/hooks';
|
||||
import { Component } from '@wordpress/element';
|
||||
import { Component, createRef, Fragment } from '@wordpress/element';
|
||||
import { compose } from '@wordpress/compose';
|
||||
import { focus } from '@wordpress/dom';
|
||||
import { withDispatch } from '@wordpress/data';
|
||||
import { get } from 'lodash';
|
||||
import PropTypes from 'prop-types';
|
||||
|
@ -24,6 +25,8 @@ import { QUERY_DEFAULTS } from 'wc-api/constants';
|
|||
import withSelect from 'wc-api/with-select';
|
||||
import { extendTableData } from './utils';
|
||||
|
||||
import './style.scss';
|
||||
|
||||
const TABLE_FILTER = 'woocommerce_admin_report_table';
|
||||
|
||||
/**
|
||||
|
@ -34,6 +37,8 @@ class ReportTable extends Component {
|
|||
super( props );
|
||||
|
||||
this.onColumnsChange = this.onColumnsChange.bind( this );
|
||||
this.onPageChange = this.onPageChange.bind( this );
|
||||
this.scrollPointRef = createRef();
|
||||
}
|
||||
|
||||
onColumnsChange( shownColumns ) {
|
||||
|
@ -49,6 +54,18 @@ class ReportTable extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
onPageChange() {
|
||||
this.scrollPointRef.current.scrollIntoView();
|
||||
const tableElement = this.scrollPointRef.current.nextSibling.querySelector(
|
||||
'.woocommerce-table__table'
|
||||
);
|
||||
const focusableElements = focus.focusable.find( tableElement );
|
||||
|
||||
if ( focusableElements.length ) {
|
||||
focusableElements[ 0 ].focus();
|
||||
}
|
||||
}
|
||||
|
||||
filterShownHeaders( headers, hiddenKeys ) {
|
||||
if ( ! hiddenKeys || ! hiddenKeys.length ) {
|
||||
return headers;
|
||||
|
@ -102,19 +119,27 @@ class ReportTable extends Component {
|
|||
const filteredHeaders = this.filterShownHeaders( headers, userPrefColumns );
|
||||
|
||||
return (
|
||||
<TableCard
|
||||
downloadable={ downloadable }
|
||||
headers={ filteredHeaders }
|
||||
ids={ ids }
|
||||
isLoading={ isLoading }
|
||||
onQueryChange={ onQueryChange }
|
||||
onColumnsChange={ this.onColumnsChange }
|
||||
rows={ rows }
|
||||
rowsPerPage={ parseInt( query.per_page ) || QUERY_DEFAULTS.pageSize }
|
||||
summary={ summary }
|
||||
totalRows={ totalResults }
|
||||
{ ...tableProps }
|
||||
/>
|
||||
<Fragment>
|
||||
<div
|
||||
className="woocommerce-report-table__scroll-point"
|
||||
ref={ this.scrollPointRef }
|
||||
aria-hidden
|
||||
/>
|
||||
<TableCard
|
||||
downloadable={ downloadable }
|
||||
headers={ filteredHeaders }
|
||||
ids={ ids }
|
||||
isLoading={ isLoading }
|
||||
onQueryChange={ onQueryChange }
|
||||
onColumnsChange={ this.onColumnsChange }
|
||||
onPageChange={ this.onPageChange }
|
||||
rows={ rows }
|
||||
rowsPerPage={ parseInt( query.per_page ) || QUERY_DEFAULTS.pageSize }
|
||||
summary={ summary }
|
||||
totalRows={ totalResults }
|
||||
{ ...tableProps }
|
||||
/>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
/** @format */
|
||||
|
||||
.woocommerce-report-table__scroll-point {
|
||||
position: relative;
|
||||
top: -#{$adminbar-height + $gap};
|
||||
|
||||
@include breakpoint( '<782px' ) {
|
||||
top: -#{$adminbar-height-mobile + $gap};
|
||||
}
|
||||
|
||||
.woocommerce-feature-enabled-activity-panels & {
|
||||
top: -#{$adminbar-height + $large-header-height + $gap};
|
||||
|
||||
@include breakpoint( '<782px' ) {
|
||||
top: -#{$adminbar-height-mobile + $small-header-height + $gap};
|
||||
}
|
||||
|
||||
@include breakpoint( '782px-960px' ) {
|
||||
top: -#{$adminbar-height + $medium-header-height + $gap};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -116,7 +116,10 @@ class ProductStockCard extends Component {
|
|||
render() {
|
||||
const { product } = this.props;
|
||||
const title = (
|
||||
<Link href={ 'post.php?action=edit&post=' + ( product.parent_id || product.id ) } type="wp-admin">
|
||||
<Link
|
||||
href={ 'post.php?action=edit&post=' + ( product.parent_id || product.id ) }
|
||||
type="wp-admin"
|
||||
>
|
||||
{ product.name }
|
||||
</Link>
|
||||
);
|
||||
|
|
|
@ -6,26 +6,24 @@
|
|||
align-items: center;
|
||||
position: fixed;
|
||||
right: 0;
|
||||
height: 80px;
|
||||
height: $medium-header-height;
|
||||
|
||||
@include breakpoint( '<782px' ) {
|
||||
position: relative;
|
||||
background: $white;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
top: -3px;
|
||||
width: 100vw;
|
||||
display: none;
|
||||
height: 60px;
|
||||
flex: 1 100%;
|
||||
}
|
||||
|
||||
@include breakpoint( '782px-960px' ) {
|
||||
max-width: 280px;
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
@include breakpoint( '>960px' ) {
|
||||
height: $large-header-height;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
|
@ -37,11 +35,11 @@
|
|||
.woocommerce-layout__activity-panel-tabs {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
height: 60px;
|
||||
height: $medium-header-height;
|
||||
justify-content: flex-end;
|
||||
|
||||
@include breakpoint( '>960px' ) {
|
||||
height: 80px;
|
||||
height: $large-header-height;
|
||||
}
|
||||
|
||||
.dashicon,
|
||||
|
@ -78,10 +76,10 @@
|
|||
min-width: 80px;
|
||||
width: 100%;
|
||||
font-size: 11px;
|
||||
height: 60px;
|
||||
height: $medium-header-height;
|
||||
@include breakpoint( '>960px' ) {
|
||||
font-size: 13px;
|
||||
height: 80px;
|
||||
height: $large-header-height;
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
|
@ -149,9 +147,9 @@
|
|||
.woocommerce-layout__activity-panel-mobile-toggle {
|
||||
margin-right: 10px;
|
||||
max-width: 48px;
|
||||
height: 46px;
|
||||
height: $small-header-height;
|
||||
position: fixed;
|
||||
top: 50px;
|
||||
top: $adminbar-height-mobile;
|
||||
right: 0;
|
||||
@include breakpoint( '>782px' ) {
|
||||
display: none;
|
||||
|
@ -194,31 +192,26 @@
|
|||
}
|
||||
|
||||
.woocommerce-layout__activity-panel-wrapper {
|
||||
height: calc(100vh - 80px);
|
||||
min-height: calc(100vh - 80px);
|
||||
height: calc(100vh - #{$medium-header-height + $small-header-height + $adminbar-height-mobile});
|
||||
background: $core-grey-light-200;
|
||||
box-shadow: 0 12px 12px 0 rgba(85, 93, 102, 0.3);
|
||||
width: 0;
|
||||
@include activity-panel-slide();
|
||||
position: fixed;
|
||||
right: 0;
|
||||
top: 92px;
|
||||
top: #{$medium-header-height + $small-header-height + $adminbar-height-mobile};
|
||||
z-index: 1000;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
|
||||
// Extra padding is needed at the bottom of the wrapper because of our positioning, height, and overflow rules. Otherwise, some content can get cut off.
|
||||
padding-bottom: $gap-small * 6;
|
||||
@include breakpoint( '782px-960px' ) {
|
||||
padding-bottom: $gap-small;
|
||||
}
|
||||
@include breakpoint( '>960px' ) {
|
||||
top: 112px;
|
||||
padding-bottom: $gap * 2;
|
||||
height: calc(100vh - #{$medium-header-height + $adminbar-height});
|
||||
top: #{$medium-header-height + $adminbar-height};
|
||||
}
|
||||
|
||||
@include breakpoint( '<782px' ) {
|
||||
top: 153px;
|
||||
@include breakpoint( '>960px' ) {
|
||||
height: calc(100vh - #{$large-header-height + $adminbar-height});
|
||||
top: #{$large-header-height + $adminbar-height};
|
||||
}
|
||||
|
||||
&.is-open {
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
box-sizing: border-box;
|
||||
border-bottom: 1px solid $white;
|
||||
padding: 0;
|
||||
height: 80px;
|
||||
height: $large-header-height;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
top: $adminbar-height;
|
||||
|
@ -20,12 +20,12 @@
|
|||
|
||||
@include breakpoint( '<782px' ) {
|
||||
top: $adminbar-height-mobile;
|
||||
height: 50px;
|
||||
height: $small-header-height;
|
||||
flex-flow: row wrap;
|
||||
}
|
||||
|
||||
@include breakpoint( '782px-960px' ) {
|
||||
height: 60px;
|
||||
height: $medium-header-height;
|
||||
}
|
||||
|
||||
.woocommerce-layout__header-breadcrumbs {
|
||||
|
@ -34,18 +34,18 @@
|
|||
padding: 0 0 0 $fallback-gutter-large;
|
||||
padding: 0 0 0 $gutter-large;
|
||||
flex: 1 auto;
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
height: $small-header-height;
|
||||
line-height: $small-header-height;
|
||||
background: $white;
|
||||
|
||||
@include breakpoint( '782px-960px' ) {
|
||||
height: 60px;
|
||||
line-height: 60px;
|
||||
height: $medium-header-height;
|
||||
line-height: $medium-header-height;
|
||||
}
|
||||
|
||||
@include breakpoint( '>960px' ) {
|
||||
height: 80px;
|
||||
line-height: 80px;
|
||||
height: $large-header-height;
|
||||
line-height: $large-header-height;
|
||||
}
|
||||
|
||||
span + span::before {
|
||||
|
|
|
@ -13,6 +13,11 @@ $gap-small: 12px;
|
|||
$gap-smaller: 8px;
|
||||
$gap-smallest: 4px;
|
||||
|
||||
// Header
|
||||
$small-header-height: 50px;
|
||||
$medium-header-height: 60px;
|
||||
$large-header-height: 80px;
|
||||
|
||||
// @todo Remove this spacing variable
|
||||
$spacing: 16px;
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# unreleased
|
||||
- TableCard component: new `onPageChange` prop.
|
||||
- Pagination no longer considers `0` a valid input and triggers `onPageChange` on the input blur event.
|
||||
- Tweaks to SummaryListPlaceholder height in order to better match SummaryNumber.
|
||||
|
||||
|
|
|
@ -67,10 +67,10 @@ class Pagination extends Component {
|
|||
}
|
||||
|
||||
onInputBlur( event ) {
|
||||
const { onPageChange } = this.props;
|
||||
const { onPageChange, page } = this.props;
|
||||
const newPage = parseInt( event.target.value, 10 );
|
||||
|
||||
if ( isFinite( newPage ) && newPage > 0 && this.pageCount && this.pageCount >= newPage ) {
|
||||
if ( newPage !== page && isFinite( newPage ) && newPage > 0 && this.pageCount && this.pageCount >= newPage ) {
|
||||
onPageChange( newPage );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@ class TableCard extends Component {
|
|||
this.onColumnToggle = this.onColumnToggle.bind( this );
|
||||
this.onClickDownload = this.onClickDownload.bind( this );
|
||||
this.onCompare = this.onCompare.bind( this );
|
||||
this.onPageChange = this.onPageChange.bind( this );
|
||||
this.onSearch = this.onSearch.bind( this );
|
||||
this.selectRow = this.selectRow.bind( this );
|
||||
this.selectAllRows = this.selectAllRows.bind( this );
|
||||
|
@ -168,6 +169,16 @@ class TableCard extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
onPageChange( ...params ) {
|
||||
const { onPageChange, onQueryChange } = this.props;
|
||||
if ( onPageChange ) {
|
||||
onPageChange( ...params );
|
||||
}
|
||||
if ( onQueryChange ) {
|
||||
onQueryChange( 'page' )( ...params );
|
||||
}
|
||||
}
|
||||
|
||||
onSearch( values ) {
|
||||
const { compareParam, searchBy, baseSearchQuery } = this.props;
|
||||
// A comma is used as a separator between search terms, so we want to escape
|
||||
|
@ -380,7 +391,7 @@ class TableCard extends Component {
|
|||
page={ parseInt( query.page ) || 1 }
|
||||
perPage={ rowsPerPage }
|
||||
total={ totalRows }
|
||||
onPageChange={ onQueryChange( 'page' ) }
|
||||
onPageChange={ this.onPageChange }
|
||||
onPerPageChange={ onQueryChange( 'per_page' ) }
|
||||
/>
|
||||
|
||||
|
|
Loading…
Reference in New Issue