mirror of
https://github.com/woocommerce/woocommerce.git
synced 2025-08-18 10:21:16 +08:00
Fix: Gradient overlay on TableCard does not disappear on resize (#60208)
Fixes a bug where the linear gradient overlay on tables would not disappear when resizing the viewport back to a larger size. The issue was affecting tables in the WooPayments plugin.
This commit is contained in:
parent
e74cf32cf5
commit
6c7fad08d5
4 changed files with 184 additions and 17 deletions
|
@ -0,0 +1,4 @@
|
|||
Significance: patch
|
||||
Type: fix
|
||||
|
||||
Fix linear gradient overlay not disappearing on table resize
|
|
@ -10,6 +10,60 @@ import { Button, Notice } from '@wordpress/components';
|
|||
*/
|
||||
import { headers, rows, summary } from './index';
|
||||
|
||||
// Create headers with many columns to trigger horizontal scrolling
|
||||
const wideHeaders = [
|
||||
{ key: 'month', label: 'Month' },
|
||||
{ key: 'orders', label: 'Orders' },
|
||||
{ key: 'revenue', label: 'Revenue' },
|
||||
{ key: 'profit', label: 'Profit' },
|
||||
{ key: 'taxes', label: 'Taxes' },
|
||||
{ key: 'shipping', label: 'Shipping' },
|
||||
{ key: 'discounts', label: 'Discounts' },
|
||||
{ key: 'refunds', label: 'Refunds' },
|
||||
{ key: 'fees', label: 'Fees' },
|
||||
{ key: 'net', label: 'Net Revenue' },
|
||||
];
|
||||
|
||||
// Create rows with many columns
|
||||
const wideRows = [
|
||||
[
|
||||
{ display: 'January', value: 1 },
|
||||
{ display: 10, value: 10 },
|
||||
{ display: '$530.00', value: 530 },
|
||||
{ display: '$450.00', value: 450 },
|
||||
{ display: '$80.00', value: 80 },
|
||||
{ display: '$25.00', value: 25 },
|
||||
{ display: '$15.00', value: 15 },
|
||||
{ display: '$0.00', value: 0 },
|
||||
{ display: '$5.00', value: 5 },
|
||||
{ display: '$405.00', value: 405 },
|
||||
],
|
||||
[
|
||||
{ display: 'February', value: 2 },
|
||||
{ display: 13, value: 13 },
|
||||
{ display: '$675.00', value: 675 },
|
||||
{ display: '$580.00', value: 580 },
|
||||
{ display: '$95.00', value: 95 },
|
||||
{ display: '$30.00', value: 30 },
|
||||
{ display: '$20.00', value: 20 },
|
||||
{ display: '$0.00', value: 0 },
|
||||
{ display: '$8.00', value: 8 },
|
||||
{ display: '$517.00', value: 517 },
|
||||
],
|
||||
[
|
||||
{ display: 'March', value: 3 },
|
||||
{ display: 9, value: 9 },
|
||||
{ display: '$460.00', value: 460 },
|
||||
{ display: '$390.00', value: 390 },
|
||||
{ display: '$70.00', value: 70 },
|
||||
{ display: '$22.00', value: 22 },
|
||||
{ display: '$18.00', value: 18 },
|
||||
{ display: '$0.00', value: 0 },
|
||||
{ display: '$6.00', value: 6 },
|
||||
{ display: '$344.00', value: 344 },
|
||||
],
|
||||
];
|
||||
|
||||
const TableCardExample = () => {
|
||||
const [ { query }, setState ] = useState( {
|
||||
query: {
|
||||
|
@ -124,9 +178,36 @@ const TableCardWithTablePrefaceExample = () => {
|
|||
);
|
||||
};
|
||||
|
||||
const TableCardWideExample = () => {
|
||||
const [ { query }, setState ] = useState( {
|
||||
query: {
|
||||
paged: 1,
|
||||
},
|
||||
} );
|
||||
return (
|
||||
<TableCard
|
||||
title="Revenue with many columns (test horizontal scroll)"
|
||||
rows={ wideRows }
|
||||
headers={ wideHeaders }
|
||||
onQueryChange={ ( param ) => ( value ) =>
|
||||
setState( {
|
||||
// @ts-expect-error: ignore for storybook
|
||||
query: {
|
||||
[ param ]: value,
|
||||
},
|
||||
} ) }
|
||||
query={ query }
|
||||
rowsPerPage={ 7 }
|
||||
totalRows={ 10 }
|
||||
summary={ summary }
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const Basic = () => <TableCardExample />;
|
||||
export const Actions = () => <TableCardWithActionsExample />;
|
||||
export const TablePreface = () => <TableCardWithTablePrefaceExample />;
|
||||
export const WideTable = () => <TableCardWideExample />;
|
||||
|
||||
export default {
|
||||
title: 'Components/TableCard',
|
||||
|
|
|
@ -129,22 +129,36 @@ const Table: React.VFC< TableProps > = ( {
|
|||
const updateTableShadow = () => {
|
||||
const table = container.current;
|
||||
|
||||
if ( table?.scrollWidth && table?.scrollHeight && table?.offsetWidth ) {
|
||||
const scrolledToEnd =
|
||||
table.scrollWidth - table.scrollLeft <= table.offsetWidth;
|
||||
if ( scrolledToEnd && isScrollableRight ) {
|
||||
setIsScrollableRight( false );
|
||||
} else if ( ! scrolledToEnd && ! isScrollableRight ) {
|
||||
setIsScrollableRight( true );
|
||||
}
|
||||
|
||||
const scrolledToStart = table.scrollLeft === 0;
|
||||
if ( scrolledToStart && isScrollableLeft ) {
|
||||
setIsScrollableLeft( false );
|
||||
} else if ( ! scrolledToStart && ! isScrollableLeft ) {
|
||||
setIsScrollableLeft( true );
|
||||
}
|
||||
if ( ! table ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get current dimensions
|
||||
const scrollWidth = table.scrollWidth;
|
||||
const offsetWidth = table.offsetWidth;
|
||||
const scrollLeft = table.scrollLeft;
|
||||
|
||||
// Check if the table is actually scrollable
|
||||
const isTableScrollable = scrollWidth > offsetWidth;
|
||||
|
||||
// If table is not scrollable, remove all scroll indicators
|
||||
if ( ! isTableScrollable ) {
|
||||
setIsScrollableRight( false );
|
||||
setIsScrollableLeft( false );
|
||||
// Reset scroll position when table is no longer scrollable
|
||||
if ( scrollLeft !== 0 ) {
|
||||
table.scrollLeft = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate scroll states
|
||||
const scrolledToEnd = scrollWidth - scrollLeft <= offsetWidth;
|
||||
const scrolledToStart = scrollLeft === 0;
|
||||
|
||||
// Update scroll indicators based on current state
|
||||
setIsScrollableRight( ! scrolledToEnd );
|
||||
setIsScrollableLeft( ! scrolledToStart );
|
||||
};
|
||||
|
||||
const sortedBy =
|
||||
|
@ -166,10 +180,18 @@ const Table: React.VFC< TableProps > = ( {
|
|||
const scrollable = scrollWidth > clientWidth;
|
||||
setTabIndex( scrollable ? 0 : undefined );
|
||||
updateTableShadow();
|
||||
window.addEventListener( 'resize', updateTableShadow );
|
||||
|
||||
const handleResize = () => {
|
||||
// Use requestAnimationFrame to ensure DOM has updated
|
||||
requestAnimationFrame( () => {
|
||||
updateTableShadow();
|
||||
} );
|
||||
};
|
||||
|
||||
window.addEventListener( 'resize', handleResize );
|
||||
|
||||
return () => {
|
||||
window.removeEventListener( 'resize', updateTableShadow );
|
||||
window.removeEventListener( 'resize', handleResize );
|
||||
};
|
||||
}, [] );
|
||||
|
||||
|
|
|
@ -258,4 +258,64 @@ describe( 'Table', () => {
|
|||
|
||||
expect( el ).toHaveClass( 'class-222' );
|
||||
} );
|
||||
|
||||
it( 'should remove scrollable classes when table is no longer scrollable', () => {
|
||||
// Mock a table that is initially scrollable
|
||||
const mockScrollableTable = {
|
||||
scrollWidth: 1000,
|
||||
offsetWidth: 500,
|
||||
scrollLeft: 0,
|
||||
};
|
||||
|
||||
// Mock a table that is no longer scrollable
|
||||
const mockNonScrollableTable = {
|
||||
scrollWidth: 400,
|
||||
offsetWidth: 500,
|
||||
scrollLeft: 0,
|
||||
};
|
||||
|
||||
const {} = render(
|
||||
<Table
|
||||
caption="Test table"
|
||||
headers={ mockHeaders }
|
||||
rows={ mockData }
|
||||
/>
|
||||
);
|
||||
|
||||
const tableElement = screen.getByLabelText( 'Test table' );
|
||||
|
||||
// Mock the container ref to simulate scrollable state
|
||||
Object.defineProperty( tableElement, 'scrollWidth', {
|
||||
value: mockScrollableTable.scrollWidth,
|
||||
writable: true,
|
||||
} );
|
||||
Object.defineProperty( tableElement, 'offsetWidth', {
|
||||
value: mockScrollableTable.offsetWidth,
|
||||
writable: true,
|
||||
} );
|
||||
Object.defineProperty( tableElement, 'scrollLeft', {
|
||||
value: mockScrollableTable.scrollLeft,
|
||||
writable: true,
|
||||
} );
|
||||
|
||||
// Trigger a resize event to simulate window resize
|
||||
window.dispatchEvent( new Event( 'resize' ) );
|
||||
|
||||
// Now simulate the table becoming non-scrollable
|
||||
Object.defineProperty( tableElement, 'scrollWidth', {
|
||||
value: mockNonScrollableTable.scrollWidth,
|
||||
writable: true,
|
||||
} );
|
||||
Object.defineProperty( tableElement, 'offsetWidth', {
|
||||
value: mockNonScrollableTable.offsetWidth,
|
||||
writable: true,
|
||||
} );
|
||||
|
||||
// Trigger another resize event
|
||||
window.dispatchEvent( new Event( 'resize' ) );
|
||||
|
||||
// The table should not have scrollable classes when it's not scrollable
|
||||
expect( tableElement ).not.toHaveClass( 'is-scrollable-right' );
|
||||
expect( tableElement ).not.toHaveClass( 'is-scrollable-left' );
|
||||
} );
|
||||
} );
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue