[Experimental] Product Filters Redesign: Attribute Filters: List style (#50340)
* update: new simplified markup and style * add: editor preview * add: show 15 items initially * fix: render li class for checked items * chore: naming * chore: changelog * update: set some preview items checked for styling purpose * fix: only show show more button when the list is long * chore: lint * fix: e2e tests
This commit is contained in:
parent
7e691560d4
commit
aaf3046eb6
|
@ -1,29 +0,0 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import FilterElementLabel from '@woocommerce/base-components/filter-element-label';
|
||||
import { CheckboxList } from '@woocommerce/blocks-components';
|
||||
import { AttributeTerm } from '@woocommerce/types';
|
||||
|
||||
type Props = {
|
||||
attributeTerms: AttributeTerm[];
|
||||
showCounts?: boolean;
|
||||
};
|
||||
export const AttributeCheckboxList = ( {
|
||||
attributeTerms,
|
||||
showCounts,
|
||||
}: Props ) => (
|
||||
<CheckboxList
|
||||
className="wc-block-attribute-filter style-list"
|
||||
onChange={ () => null }
|
||||
options={ attributeTerms.map( ( term ) => ( {
|
||||
label: (
|
||||
<FilterElementLabel
|
||||
name={ term.name }
|
||||
count={ showCounts ? term.count : null }
|
||||
/>
|
||||
),
|
||||
value: term.slug,
|
||||
} ) ) }
|
||||
/>
|
||||
);
|
|
@ -0,0 +1,68 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { __ } from '@wordpress/i18n';
|
||||
|
||||
/**
|
||||
* Ideally, this component should belong to packages/interactivity-components.
|
||||
* But we haven't export it as a packages so we place it here temporary.
|
||||
*/
|
||||
export const Preview = ( { items }: { items: string[] } ) => {
|
||||
const threshold = 15;
|
||||
const isLongList = items.length > threshold;
|
||||
return (
|
||||
<div className="wc-block-interactivity-components-checkbox-list">
|
||||
<ul className="wc-block-interactivity-components-checkbox-list__list">
|
||||
{ ( isLongList ? items.slice( 0, threshold ) : items ).map(
|
||||
( item, index ) => (
|
||||
<li
|
||||
key={ index }
|
||||
className="wc-block-interactivity-components-checkbox-list__item"
|
||||
>
|
||||
<label
|
||||
htmlFor={ `interactive-checkbox-${ index }` }
|
||||
className=" wc-block-interactivity-components-checkbox-list__label"
|
||||
>
|
||||
<span className="wc-block-interactive-components-checkbox-list__input-wrapper">
|
||||
<span className="wc-block-interactivity-components-checkbox-list__input-wrapper">
|
||||
<input
|
||||
name={ `interactive-checkbox-${ index }` }
|
||||
type="checkbox"
|
||||
className="wc-block-interactivity-components-checkbox-list__input"
|
||||
// Harded coded some checked items for styling purpose.
|
||||
defaultChecked={ [
|
||||
1, 3, 4,
|
||||
].includes( index ) }
|
||||
/>
|
||||
<svg
|
||||
className="wc-block-interactivity-components-checkbox-list__mark"
|
||||
viewBox="0 0 10 8"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M9.25 1.19922L3.75 6.69922L1 3.94922"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
<span className="wc-block-interactivity-components-checkbox-list__text">
|
||||
{ item }
|
||||
</span>
|
||||
</label>
|
||||
</li>
|
||||
)
|
||||
) }
|
||||
</ul>
|
||||
{ isLongList && (
|
||||
<span className="wc-block-interactivity-components-checkbox-list__show-more">
|
||||
<small>{ __( 'Show more…', 'woocommerce' ) }</small>
|
||||
</span>
|
||||
) }
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -24,10 +24,10 @@ import { EditProps, isAttributeCounts } from './types';
|
|||
import { NoAttributesPlaceholder } from './components/placeholder';
|
||||
import { getAttributeFromId } from './utils';
|
||||
import { Inspector } from './components/inspector';
|
||||
import { AttributeCheckboxList } from './components/attribute-checkbox-list';
|
||||
import { AttributeDropdown } from './components/attribute-dropdown';
|
||||
import { attributeOptionsPreview } from './constants';
|
||||
import './style.scss';
|
||||
import { Preview as CheckboxListPreview } from './components/checkbox-list-editor';
|
||||
|
||||
const ATTRIBUTES = getSetting< AttributeSetting[] >( 'attributes', [] );
|
||||
|
||||
|
@ -184,9 +184,12 @@ const Edit = ( props: EditProps ) => {
|
|||
return (
|
||||
<Wrapper>
|
||||
<Disabled>
|
||||
<AttributeCheckboxList
|
||||
showCounts={ showCounts }
|
||||
attributeTerms={ attributeOptionsPreview }
|
||||
<CheckboxListPreview
|
||||
items={ attributeOptionsPreview.map( ( term ) => {
|
||||
if ( showCounts )
|
||||
return `${ term.name } (${ term.count })`;
|
||||
return term.name;
|
||||
} ) }
|
||||
/>
|
||||
</Disabled>
|
||||
</Wrapper>
|
||||
|
@ -240,11 +243,14 @@ const Edit = ( props: EditProps ) => {
|
|||
}
|
||||
/>
|
||||
) : (
|
||||
<AttributeCheckboxList
|
||||
showCounts={ showCounts }
|
||||
attributeTerms={ attributeOptions }
|
||||
<CheckboxListPreview
|
||||
items={ attributeOptions.map( ( term ) => {
|
||||
if ( showCounts )
|
||||
return `${ term.name } (${ term.count })`;
|
||||
return term.name;
|
||||
} ) }
|
||||
/>
|
||||
) }{ ' ' }
|
||||
) }
|
||||
</Disabled>
|
||||
</Wrapper>
|
||||
);
|
||||
|
|
|
@ -20,11 +20,17 @@ export type CheckboxListContext = {
|
|||
value: string;
|
||||
checked: boolean;
|
||||
}[];
|
||||
showAll: boolean;
|
||||
};
|
||||
|
||||
store( 'woocommerce/interactivity-checkbox-list', {
|
||||
state: {},
|
||||
actions: {
|
||||
showAllItems: () => {
|
||||
const context = getContext< CheckboxListContext >();
|
||||
context.showAll = true;
|
||||
},
|
||||
|
||||
selectCheckboxItem: ( event: HTMLElementEvent< HTMLInputElement > ) => {
|
||||
const context = getContext< CheckboxListContext >();
|
||||
const value = event.target.value;
|
||||
|
|
|
@ -1,33 +1,69 @@
|
|||
// Import styles we need to render the checkbox list and checkbox control.
|
||||
@import "../../../packages/components/checkbox-list/style";
|
||||
@import "../../../packages/components/checkbox-control/style";
|
||||
|
||||
.wc-block-stock-filter-list {
|
||||
:where(.wc-block-interactivity-components-checkbox-list__list) {
|
||||
list-style: none outside;
|
||||
margin: 0;
|
||||
|
||||
li {
|
||||
label {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
input {
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
.wc-block-components-checkbox-list {
|
||||
margin: 0;
|
||||
|
||||
li {
|
||||
label {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
input {
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.wc-block-interactivity-components-checkbox-list__item.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
:where(.wc-block-interactivity-components-checkbox-list__label) {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
gap: 0.625em;
|
||||
}
|
||||
|
||||
.wc-block-interactivity-components-checkbox-list__item .wc-block-interactivity-components-checkbox-list__label {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
:where(.wc-block-interactivity-components-checkbox-list__input-wrapper) {
|
||||
display: block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
:where(.wc-block-interactivity-components-checkbox-list__input) {
|
||||
appearance: none;
|
||||
background: currentColor;
|
||||
border-radius: 2px;
|
||||
border: none;
|
||||
color: inherit;
|
||||
display: block;
|
||||
font-size: inherit;
|
||||
height: 1em;
|
||||
margin: 0;
|
||||
opacity: 0.1;
|
||||
width: 1em;
|
||||
}
|
||||
|
||||
.wc-block-interactivity-components-checkbox-list__input:checked + .wc-block-interactivity-components-checkbox-list__mark {
|
||||
display: block;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.wc-block-interactivity-components-checkbox-list__input:focus {
|
||||
outline-width: 1px;
|
||||
}
|
||||
|
||||
:where(.wc-block-interactivity-components-checkbox-list__mark) {
|
||||
box-sizing: border-box;
|
||||
display: none;
|
||||
height: 1em;
|
||||
left: 0;
|
||||
padding: 0.2em;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 1em;
|
||||
}
|
||||
|
||||
:where(.wc-block-interactivity-components-checkbox-list__show-more) {
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.wc-block-interactivity-components-checkbox-list__show-more.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ test.describe( 'Product Filter: Attribute Block', () => {
|
|||
await page.goto( '/shop' );
|
||||
|
||||
const attributes = page.locator(
|
||||
'.wc-block-components-checkbox__label'
|
||||
'.wc-block-interactivity-components-checkbox-list__label'
|
||||
);
|
||||
|
||||
await expect( attributes ).toHaveCount( 5 );
|
||||
|
@ -156,7 +156,7 @@ test.describe( 'Product Filter: Attribute Block', () => {
|
|||
await page.goto( '/shop' );
|
||||
|
||||
const attributes = page.locator(
|
||||
'.wc-block-components-checkbox__label'
|
||||
'.wc-block-interactivity-components-checkbox-list__label'
|
||||
);
|
||||
|
||||
await expect( attributes ).toHaveCount( 5 );
|
||||
|
|
|
@ -37,7 +37,7 @@ test.describe( 'Product Filter: Stock Status Block', () => {
|
|||
await page.goto( '/shop' );
|
||||
|
||||
const stockStatuses = page.locator(
|
||||
'.wc-block-components-checkbox__label'
|
||||
'.wc-block-interactivity-components-checkbox-list__label'
|
||||
);
|
||||
|
||||
await expect( stockStatuses ).toHaveCount( 2 );
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
Significance: patch
|
||||
Type: update
|
||||
Comment: Experimental: Product Filters: Attribute Filter: Update List style
|
||||
|
||||
|
|
@ -28,50 +28,82 @@ class CheckboxList {
|
|||
$items = $props['items'] ?? array();
|
||||
$checkbox_list_context = array( 'items' => $items );
|
||||
$on_change = $props['on_change'] ?? '';
|
||||
$namespace = wp_json_encode( array( 'namespace' => 'woocommerce/interactivity-checkbox-list' ), JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP );
|
||||
|
||||
$namespace = wp_json_encode( array( 'namespace' => 'woocommerce/interactivity-checkbox-list' ), JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP );
|
||||
|
||||
$checked_items = array_filter(
|
||||
$items,
|
||||
function ( $item ) {
|
||||
return $item['checked'];
|
||||
}
|
||||
);
|
||||
$show_initially = $props['show_initially'] ?? 15;
|
||||
$remaining_initial_unchecked = count( $checked_items ) > $show_initially ? count( $checked_items ) : $show_initially - count( $checked_items );
|
||||
$count = 0;
|
||||
ob_start();
|
||||
?>
|
||||
<div data-wc-interactive='<?php echo esc_attr( $namespace ); ?>'>
|
||||
<div data-wc-context='<?php echo wp_json_encode( $checkbox_list_context, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP ); ?>' >
|
||||
<div class="wc-block-stock-filter style-list">
|
||||
<ul class="wc-block-components-checkbox-list">
|
||||
<?php foreach ( $items as $item ) { ?>
|
||||
<?php
|
||||
$item['id'] = $item['id'] ?? uniqid( 'checkbox-' );
|
||||
// translators: %s: checkbox label.
|
||||
$i18n_label = sprintf( __( 'Checkbox: %s', 'woocommerce' ), $item['aria_label'] ?? '' );
|
||||
?>
|
||||
<li data-wc-key="<?php echo esc_attr( $item['id'] ); ?>">
|
||||
<div class="wc-block-components-checkbox">
|
||||
<label for="<?php echo esc_attr( $item['id'] ); ?>">
|
||||
<input
|
||||
id="<?php echo esc_attr( $item['id'] ); ?>"
|
||||
class="wc-block-components-checkbox__input"
|
||||
type="checkbox"
|
||||
aria-invalid="false"
|
||||
aria-label="<?php echo esc_attr( $i18n_label ); ?>"
|
||||
data-wc-on--change--select-item="actions.selectCheckboxItem"
|
||||
data-wc-on--change--parent-action="<?php echo esc_attr( $on_change ); ?>"
|
||||
value="<?php echo esc_attr( $item['value'] ); ?>"
|
||||
<?php checked( $item['checked'], 1 ); ?>
|
||||
>
|
||||
<svg class="wc-block-components-checkbox__mark" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 20">
|
||||
<path d="M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z"></path>
|
||||
</svg>
|
||||
<span class="wc-block-components-checkbox__label">
|
||||
<?php // The label can be HTML, so we don't want to escape it. ?>
|
||||
<?php // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
<?php echo $item['label']; ?>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</li>
|
||||
<?php } ?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="wc-block-interactivity-components-checkbox-list"
|
||||
data-wc-interactive='<?php echo esc_attr( $namespace ); ?>'
|
||||
data-wc-context='<?php echo wp_json_encode( $checkbox_list_context, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP ); ?>'
|
||||
>
|
||||
<ul class="wc-block-interactivity-components-checkbox-list__list">
|
||||
<?php foreach ( $items as $item ) { ?>
|
||||
<?php
|
||||
$item['id'] = $item['id'] ?? uniqid( 'checkbox-' );
|
||||
// translators: %s: checkbox label.
|
||||
$i18n_label = sprintf( __( 'Checkbox: %s', 'woocommerce' ), $item['aria_label'] ?? '' );
|
||||
?>
|
||||
<li
|
||||
data-wc-key="<?php echo esc_attr( $item['id'] ); ?>"
|
||||
<?php
|
||||
if ( ! $item['checked'] ) :
|
||||
if ( $count >= $remaining_initial_unchecked ) :
|
||||
?>
|
||||
class="wc-block-interactivity-components-checkbox-list__item hidden"
|
||||
data-wc-class--hidden="!context.showAll"
|
||||
<?php else : ?>
|
||||
<?php ++$count; ?>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
class="wc-block-interactivity-components-checkbox-list__item"
|
||||
>
|
||||
<label
|
||||
class="wc-block-interactivity-components-checkbox-list__label"
|
||||
for="<?php echo esc_attr( $item['id'] ); ?>"
|
||||
>
|
||||
<span class="wc-block-interactivity-components-checkbox-list__input-wrapper">
|
||||
<input
|
||||
id="<?php echo esc_attr( $item['id'] ); ?>"
|
||||
class="wc-block-interactivity-components-checkbox-list__input"
|
||||
type="checkbox"
|
||||
aria-invalid="false"
|
||||
aria-label="<?php echo esc_attr( $i18n_label ); ?>"
|
||||
data-wc-on--change--select-item="actions.selectCheckboxItem"
|
||||
data-wc-on--change--parent-action="<?php echo esc_attr( $on_change ); ?>"
|
||||
value="<?php echo esc_attr( $item['value'] ); ?>"
|
||||
<?php checked( $item['checked'], 1 ); ?>
|
||||
>
|
||||
<svg class="wc-block-interactivity-components-checkbox-list__mark" viewBox="0 0 10 8" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M9.25 1.19922L3.75 6.69922L1 3.94922" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
</span>
|
||||
<span class="wc-block-interactivity-components-checkbox-list__text">
|
||||
<?php echo wp_kses_post( $item['label'] ); ?>
|
||||
</span>
|
||||
</label>
|
||||
</li>
|
||||
<?php } ?>
|
||||
</ul>
|
||||
<?php if ( count( $items ) > $show_initially ) : ?>
|
||||
<span
|
||||
role="button"
|
||||
class="wc-block-interactivity-components-checkbox-list__show-more"
|
||||
data-wc-class--hidden="context.showAll"
|
||||
data-wc-on--click="actions.showAllItems"
|
||||
>
|
||||
<small role="presentation"><?php echo esc_html__( 'Show more...', 'woocommerce' ); ?></small>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php
|
||||
return ob_get_clean();
|
||||
|
|
Loading…
Reference in New Issue