The variations table should match the height of number of rows selected (#41140)

* Remove fixed height to the variations table and add per row skeletong when loading

* Add changelog file

* Add last variations instead of the current per page var given that there it is not accessible anymore
This commit is contained in:
Maikel David Pérez Gómez 2023-11-15 15:42:48 -03:00 committed by GitHub
parent 8486dfcdba
commit c416b57a94
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 259 additions and 147 deletions

View File

@ -0,0 +1,4 @@
Significance: minor
Type: add
The variations table should match the height of number of rows selected

View File

@ -3,6 +3,7 @@
@import "./pagination/styles.scss";
@import "./table-empty-state/styles.scss";
@import "./variations-filter/styles.scss";
@import "./table-row-skeleton/styles.scss";
$table-row-height: calc($grid-unit * 9);
@ -39,11 +40,6 @@ $table-row-height: calc($grid-unit * 9);
}
}
&__table {
height: $table-row-height * 5;
overflow: auto;
}
&__selection {
.components-checkbox-control__input[type="checkbox"] {
&:not(:checked):not(:focus) {

View File

@ -0,0 +1 @@
export * from './table-row-skeleton';

View File

@ -0,0 +1,51 @@
.woocommerce-table-row-skeleton {
@mixin skeleton {
@include placeholder();
background-color: $gray-200;
border-radius: $grid-unit-05;
width: $grid-unit-30;
min-height: $grid-unit-30;
}
display: grid;
grid-template-columns: 44px auto 25% 25% 88px;
padding: 0;
min-height: 9 * $grid-unit;
border: none;
align-items: center;
&__checkbox {
@include skeleton();
}
&__attribute-option {
@include skeleton();
width: 9 * $grid-unit;
}
&__regular-price,
&__quantity {
@include skeleton();
width: $grid-unit-80;
display: inline-block;
}
&__visibility-icon {
@include skeleton();
flex-shrink: 0;
}
&__edit-link {
@include skeleton();
width: $grid-unit-70;
height: $grid-unit-40 + $grid-unit-05;
flex-shrink: 0;
}
&__menu-toggle {
@include skeleton();
width: $grid-unit-40 + $grid-unit-05;
height: $grid-unit-40 + $grid-unit-05;
flex-shrink: 0;
}
}

View File

@ -0,0 +1,47 @@
/**
* External dependencies
*/
import { createElement } from '@wordpress/element';
export function TableRowSkeleton() {
return (
<div className="woocommerce-sortable__item" aria-hidden="true">
<div className="woocommerce-list-item woocommerce-table-row-skeleton">
<div className="woocommerce-sortable__handle" />
<div className="woocommerce-product-variations__selection">
<div className="woocommerce-table-row-skeleton__checkbox" />
</div>
<div className="woocommerce-product-variations__attributes">
{ Array( 3 )
.fill( 0 )
.map( ( _, index ) => (
<div
key={ index }
className="woocommerce-tag woocommerce-product-variations__attribute"
>
<div className="woocommerce-table-row-skeleton__attribute-option" />
</div>
) ) }
</div>
<div className="woocommerce-product-variations__price">
<div className="woocommerce-table-row-skeleton__regular-price" />
</div>
<div className="woocommerce-product-variations__quantity">
<div className="woocommerce-table-row-skeleton__quantity" />
</div>
<div className="woocommerce-product-variations__actions">
<div className="woocommerce-table-row-skeleton__visibility-icon" />
<div className="woocommerce-table-row-skeleton__edit-link" />
<div className="woocommerce-table-row-skeleton__menu-toggle" />
</div>
</div>
</div>
);
}

View File

@ -41,6 +41,7 @@ import { Pagination } from './pagination';
import { EmptyTableState } from './table-empty-state';
import { VariationsFilter } from './variations-filter';
import { useVariations } from './use-variations';
import { TableRowSkeleton } from './table-row-skeleton';
const NOT_VISIBLE_TEXT = __( 'Not visible to customers', 'woocommerce' );
@ -302,16 +303,6 @@ export const VariationsTable = forwardRef<
return (
<div className="woocommerce-product-variations" ref={ ref }>
{ ( isLoading || isGenerating ) && (
<div className="woocommerce-product-variations__loading">
<Spinner />
{ isGenerating && (
<span>
{ __( 'Generating variations…', 'woocommerce' ) }
</span>
) }
</div>
) }
{ noticeText && (
<Notice
status={ noticeStatus }
@ -405,148 +396,170 @@ export const VariationsTable = forwardRef<
</div>
) }
<Sortable className="woocommerce-product-variations__table">
{ variations.map( ( variation ) => (
<ListItem key={ `${ variation.id }` }>
<div className="woocommerce-product-variations__selection">
{ isUpdating[ variation.id ] ? (
<Spinner />
) : (
<CheckboxControl
value={ variation.id }
checked={ isSelected( variation ) }
onChange={ onSelect( variation ) }
disabled={ isSelectingAll }
/>
) }
</div>
<div className="woocommerce-product-variations__attributes">
{ variation.attributes.map( ( attribute ) => {
const tag = (
/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */
/* @ts-ignore Additional props are not required. */
<Tag
id={ attribute.id }
className="woocommerce-product-variations__attribute"
key={ attribute.id }
label={ truncate( attribute.option, {
length: PRODUCT_VARIATION_TITLE_LIMIT,
} ) }
screenReaderLabel={ attribute.option }
/>
);
return attribute.option.length <=
PRODUCT_VARIATION_TITLE_LIMIT ? (
tag
{ isLoading || isGenerating ? (
<div
className="woocommerce-product-variations__table"
aria-label={
isGenerating
? __( 'Generating variations…', 'woocommerce' )
: __( 'Loading variations…', 'woocommerce' )
}
>
{ Array.from( { length: variations.length || 5 } ).map(
( _, index ) => (
<TableRowSkeleton key={ index } />
)
) }
</div>
) : (
<Sortable className="woocommerce-product-variations__table">
{ variations.map( ( variation ) => (
<ListItem key={ `${ variation.id }` }>
<div className="woocommerce-product-variations__selection">
{ isUpdating[ variation.id ] ? (
<Spinner />
) : (
<Tooltip
key={ attribute.id }
text={ attribute.option }
position="top center"
>
<span>{ tag }</span>
</Tooltip>
);
} ) }
</div>
<div
className={ classnames(
'woocommerce-product-variations__price',
{
'woocommerce-product-variations__price--fade':
variation.status === 'private',
}
) }
>
{ variation.on_sale && (
<span className="woocommerce-product-variations__sale-price">
{ formatAmount( variation.sale_price ) }
</span>
) }
<span
<CheckboxControl
value={ variation.id }
checked={ isSelected( variation ) }
onChange={ onSelect( variation ) }
disabled={ isSelectingAll }
/>
) }
</div>
<div className="woocommerce-product-variations__attributes">
{ variation.attributes.map( ( attribute ) => {
const tag = (
/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */
/* @ts-ignore Additional props are not required. */
<Tag
id={ attribute.id }
className="woocommerce-product-variations__attribute"
key={ attribute.id }
label={ truncate(
attribute.option,
{
length: PRODUCT_VARIATION_TITLE_LIMIT,
}
) }
screenReaderLabel={
attribute.option
}
/>
);
return attribute.option.length <=
PRODUCT_VARIATION_TITLE_LIMIT ? (
tag
) : (
<Tooltip
key={ attribute.id }
text={ attribute.option }
position="top center"
>
<span>{ tag }</span>
</Tooltip>
);
} ) }
</div>
<div
className={ classnames(
'woocommerce-product-variations__regular-price',
'woocommerce-product-variations__price',
{
'woocommerce-product-variations__regular-price--on-sale':
variation.on_sale,
'woocommerce-product-variations__price--fade':
variation.status === 'private',
}
) }
>
{ formatAmount( variation.regular_price ) }
</span>
</div>
<div
className={ classnames(
'woocommerce-product-variations__quantity',
{
'woocommerce-product-variations__quantity--fade':
variation.status === 'private',
}
) }
>
{ variation.regular_price && (
<>
<span
className={ classnames(
'woocommerce-product-variations__status-dot',
getProductStockStatusClass(
variation
)
) }
>
{ variation.on_sale && (
<span className="woocommerce-product-variations__sale-price">
{ formatAmount( variation.sale_price ) }
</span>
{ getProductStockStatus( variation ) }
</>
) }
</div>
<div className="woocommerce-product-variations__actions">
{ ( variation.status === 'private' ||
! variation.regular_price ) && (
<Tooltip
// @ts-expect-error className is missing in TS, should remove this when it is included.
className="woocommerce-attribute-list-item__actions-tooltip"
position="top center"
text={ NOT_VISIBLE_TEXT }
) }
<span
className={ classnames(
'woocommerce-product-variations__regular-price',
{
'woocommerce-product-variations__regular-price--on-sale':
variation.on_sale,
}
) }
>
<div className="woocommerce-attribute-list-item__actions-icon-wrapper">
<HiddenIcon className="woocommerce-attribute-list-item__actions-icon-wrapper-icon" />
</div>
</Tooltip>
) }
{ ! areSomeSelected && (
<>
<Button
href={ getEditVariationLink(
variation
) }
onClick={ editVariationClickHandler(
variation
) }
{ formatAmount( variation.regular_price ) }
</span>
</div>
<div
className={ classnames(
'woocommerce-product-variations__quantity',
{
'woocommerce-product-variations__quantity--fade':
variation.status === 'private',
}
) }
>
{ variation.regular_price && (
<>
<span
className={ classnames(
'woocommerce-product-variations__status-dot',
getProductStockStatusClass(
variation
)
) }
>
</span>
{ getProductStockStatus( variation ) }
</>
) }
</div>
<div className="woocommerce-product-variations__actions">
{ ( variation.status === 'private' ||
! variation.regular_price ) && (
<Tooltip
// @ts-expect-error className is missing in TS, should remove this when it is included.
className="woocommerce-attribute-list-item__actions-tooltip"
position="top center"
text={ NOT_VISIBLE_TEXT }
>
{ __( 'Edit', 'woocommerce' ) }
</Button>
<div className="woocommerce-attribute-list-item__actions-icon-wrapper">
<HiddenIcon className="woocommerce-attribute-list-item__actions-icon-wrapper-icon" />
</div>
</Tooltip>
) }
<VariationActionsMenu
selection={ variation }
onChange={ ( value ) =>
handleVariationChange( {
id: variation.id,
...value,
} )
}
onDelete={ ( { id } ) =>
handleDeleteVariationClick( id )
}
/>
</>
) }
</div>
</ListItem>
) ) }
</Sortable>
{ ! areSomeSelected && (
<>
<Button
href={ getEditVariationLink(
variation
) }
onClick={ editVariationClickHandler(
variation
) }
>
{ __( 'Edit', 'woocommerce' ) }
</Button>
<VariationActionsMenu
selection={ variation }
onChange={ ( value ) =>
handleVariationChange( {
id: variation.id,
...value,
} )
}
onDelete={ ( { id } ) =>
handleDeleteVariationClick( id )
}
/>
</>
) }
</div>
</ListItem>
) ) }
</Sortable>
) }
{ totalCount > 5 && (
<Pagination