Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add a11y tab component to plp facets #19244

Draft
wants to merge 91 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
91 commits
Select commit Hold shift + click to select a range
5b1a887
feat: Agnostic a11y-tabs component
Zeyber Apr 27, 2021
d44be15
Merge branch 'develop' into feature/GH-11637
Zeyber May 11, 2021
f5a1a35
Add tab/accordian modes
Zeyber May 12, 2021
3b11487
order for accordian
Zeyber May 13, 2021
f73e778
Add pdp styling
Zeyber May 14, 2021
a1b5146
Merge branch 'develop' into feature/GH-11637
Zeyber May 17, 2021
d4bfb9f
start moving tabs to facets
Zeyber May 18, 2021
6a2dbcd
experimenting with facets
Zeyber May 25, 2021
4bfbe50
get tabs working in facets
Zeyber Jun 1, 2021
7650c1c
Merge branch 'develop' into feature/GH-11637
Zeyber Jul 19, 2021
5038041
Merge branch 'feature/GH-11637' of https://github.com/SAP/cloud-comme…
Zeyber Jul 19, 2021
02b2d12
Make tabs collapsable in accordian mode and tidy up
Zeyber Jul 22, 2021
c05a32e
changes
Zeyber Jul 29, 2021
1a471bd
Merge branch 'develop' into feature/GH-11637
Zeyber Aug 2, 2021
4c2d829
commit changes
Zeyber Aug 2, 2021
77e6e24
Merge branch 'develop' into feature/GH-11637
Zeyber Aug 4, 2021
2f71b4a
Merge branch 'feature/GH-11637' of https://github.com/SAP/spartacus i…
Zeyber Aug 4, 2021
48b9d18
various improvements
Zeyber Aug 9, 2021
a7703b9
Merge branch 'develop' into feature/GH-11637
Zeyber Oct 12, 2021
88e6d4c
format tab paragraph container dom
Zeyber Oct 12, 2021
ca986cd
Merge branch 'develop' into feature/GH-11637
Zeyber Oct 13, 2021
2638f73
bump feature level and fix imports
Zeyber Oct 13, 2021
6ae794f
activate feature
Zeyber Oct 14, 2021
cd43233
make separate tab-panel component
Zeyber Oct 15, 2021
c9a51ad
Merge branch 'develop' into feature/GH-11637
Zeyber Oct 20, 2021
284762d
moving stuff and commenting
Zeyber Oct 21, 2021
6e582d8
Merge branch 'develop' into feature/GH-11637
Zeyber Oct 22, 2021
88ec4b7
solving review comments
Zeyber Oct 22, 2021
e2c05c2
Merge branch 'feature/GH-11637' of https://github.com/SAP/spartacus i…
Zeyber Oct 22, 2021
353efc4
add vars
Zeyber Oct 28, 2021
dbf8b53
Rename Tab.ts to tab.ts
Matejk00 Nov 18, 2021
d880711
Merge branch 'feature/GH-11637' of https://github.com/SAP/spartacus i…
Zeyber Nov 25, 2021
e494308
remove feature flags for tab paragraph component
Zeyber Nov 25, 2021
07eb8d7
add little note
Zeyber Nov 25, 2021
3d4d17c
Merge branch 'develop' into feature/GH-11637
Zeyber Nov 25, 2021
1c16284
review changes
Zeyber Nov 26, 2021
c73c4c2
review changes and style cleanup
Zeyber Nov 26, 2021
852abe9
set label via name property from cms
Zeyber Dec 8, 2021
6be58ed
Merge branch 'develop' into feature/GH-11637
Zeyber Jan 11, 2022
19e835b
use lowercase class names
Zeyber Jan 12, 2022
611f12d
drop feature flags in facet
Zeyber Jan 12, 2022
c867663
remove feature module
Zeyber Jan 12, 2022
d530881
fix facets on mobile
Zeyber Jan 17, 2022
30d4ea0
Merge branch 'develop' into feature/GH-11637
Zeyber Jan 17, 2022
a6a5ead
Merge branch 'develop' into feature/GH-11637
Zeyber Jun 3, 2024
524ee6d
Add license header
github-actions[bot] Jun 3, 2024
c1cd6ee
fix merge issues
Zeyber Jun 3, 2024
71b6beb
cleanup
Zeyber Jun 5, 2024
8032301
cleanup tabparagraphcontainer template for review
Zeyber Jun 5, 2024
01237cb
cleanup tabparagraphcontainer template for review
Zeyber Jun 5, 2024
af4c73d
fix accordian facets
Zeyber Jun 10, 2024
116acb6
Merge branch 'develop' into feature/GH-11637-pdp
Zeyber Jun 10, 2024
623651e
removing facets
Zeyber Jun 10, 2024
afb5b2e
merge
Zeyber Jun 10, 2024
b303b80
remove facets
Zeyber Jun 10, 2024
613e4e0
fix build and styling issue
Zeyber Jun 10, 2024
d24f078
fix sonar issues
Zeyber Jun 10, 2024
bed9610
prettier fix
Zeyber Jun 10, 2024
3aa2e59
fix build errors
Zeyber Jun 13, 2024
d5938bf
review changes and tests
Zeyber Jun 20, 2024
8427317
remove tab panel complexity and cleanup
Zeyber Jun 25, 2024
1ddb25a
add dep notes, aria label, clean up
Zeyber Jun 25, 2024
f03f2c6
simplify component
Zeyber Jun 28, 2024
9f8fa6e
tab panel units
Zeyber Jul 1, 2024
7e093fc
unit tests
Zeyber Jul 8, 2024
5745744
Merge branch 'develop' into feature/GH-11637-pdp
Zeyber Jul 8, 2024
1ef8b9c
prettier
Zeyber Jul 8, 2024
eca74ee
Merge branch 'feature/GH-11637-pdp' of https://github.com/SAP/spartac…
Zeyber Jul 8, 2024
1abe225
Merge branch 'develop' into feature/GH-11637-pdp
Zeyber Jul 11, 2024
088b695
e2e tests
Zeyber Jul 15, 2024
df602d8
Merge branch 'develop' into feature/GH-11637-pdp
Zeyber Jul 15, 2024
7138c2f
prettier
Zeyber Jul 19, 2024
03c830d
Merge branch 'develop' into feature/GH-11637-pdp
Zeyber Jul 19, 2024
1688351
fix build
Zeyber Jul 19, 2024
762e8d4
fix show reviews button and test issues
Zeyber Jul 19, 2024
f07d5f8
prettier fix
Zeyber Jul 19, 2024
a02767b
review changes
Zeyber Jul 22, 2024
8f8d9ef
Merge branch 'develop' into feature/GH-11637-pdp
Zeyber Jul 22, 2024
68d7772
remove unit test
Zeyber Jul 23, 2024
3a30444
review changes
Zeyber Sep 5, 2024
67e0ed3
review changes
Zeyber Sep 10, 2024
ccab287
feat: Add a11y tab component to plp facets
Zeyber Sep 16, 2024
a265f93
prettier fix
Zeyber Sep 16, 2024
1f46588
Merge branch 'develop' into feature/GH-11637-plp
Zeyber Sep 30, 2024
1b5ad96
Merge branch 'feature/GH-11637-plp' of https://github.com/SAP/spartac…
Zeyber Sep 30, 2024
8e9a109
fix dep links
Zeyber Sep 30, 2024
f9211aa
fix mobile issues, rendering and keyboard issues
Zeyber Oct 1, 2024
2abbea1
close on left key
Zeyber Oct 1, 2024
c803b3f
add observable input to tab component
Zeyber Oct 7, 2024
2a7e276
fix get title method
Zeyber Oct 7, 2024
6afb84d
add disableBorderFocus flag
Zeyber Oct 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<div
[attr.role]="mode === TAB_MODE.ACCORDIAN ? 'region' : 'tabpanel'"
[tabindex]="0"
[tabindex]="tab.disableBorderFocus ? null : 0"
[attr.aria-labelledby]="tab.id ?? null"
[attr.id]="tab.id ? 'section-' + tab.id : null"
class="active"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,20 @@
*/

import {
AfterViewInit,
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
inject,
Input,
OnDestroy,
OnInit,
QueryList,
ViewChildren,
} from '@angular/core';
import { BreakpointService } from '../../../layout/breakpoint';
import { BehaviorSubject, Observable, of } from 'rxjs';
import { map } from 'rxjs/operators';
import { BehaviorSubject, Observable, of, Subscription } from 'rxjs';
import { map, take } from 'rxjs/operators';
import { Tab, TabConfig, TAB_MODE } from './tab.model';
import { wrapIntoBounds } from './tab.utils';
import { TranslationService } from '@spartacus/core';
Expand All @@ -24,27 +28,53 @@ import { TranslationService } from '@spartacus/core';
templateUrl: './tab.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class TabComponent implements OnInit {
export class TabComponent implements OnInit, AfterViewInit, OnDestroy {
/**
* If you have nested templates that are subject to complex changes,
* it can be better to use this property instead with an Observable
* to set Tabs.
*
* Note: You should NOT set the `tabs` property if using this.
*/
@Input() tabs$: Observable<Tab[] | any>;
@Input() tabs: Tab[] | any;
@Input() config: TabConfig | any;

readonly TAB_MODE = TAB_MODE;

openTabs$: BehaviorSubject<number[]>;
mode$: Observable<TAB_MODE>;
protected breakpointService = inject(BreakpointService);
protected translationService = inject(TranslationService);
protected cd = inject(ChangeDetectorRef);

@ViewChildren('tabHeader') tabHeaders: QueryList<any>;

constructor(
protected breakpointService: BreakpointService,
protected translationService: TranslationService
) {}
openTabs$: BehaviorSubject<number[]>;
mode$: Observable<TAB_MODE>;
protected subscriptions = new Subscription();

ngOnInit(): void {
this.openTabs$ = new BehaviorSubject<number[]>(this.config?.openTabs ?? []);
this.mode$ = this.getMode();
}

ngAfterViewInit(): void {
/**
* We subscribe to the tabs observable if added and use this to set
* the `tabs` property. The input `tabs` property should not be
* initialized. It will be overwritten by this otherwise.
*/
this.subscriptions.add(
this.tabs$?.subscribe((tabs) => {
this.tabs = tabs;
this.cd.detectChanges();
})
);
}

ngOnDestroy(): void {
this.subscriptions.unsubscribe();
}

/**
* Tab selection works differently depending on the given mode.
*
Expand Down Expand Up @@ -163,15 +193,19 @@ export class TabComponent implements OnInit {
return null;
}

let header = tab.header;
if (tab.headerKey) {
this.translationService
.translate(tab.headerKey)
.pipe(take(1))
.subscribe((val) => {
header = val;
});
}

return (
// Show expanded or collapsed.
(this.isOpen(index) ? 'Collapse' : 'Expand') +
' ' +
// Show the translation key for header if available.
// Otherwise fallback to header string value.
(tab.headerKey
? this.translationService.translate(tab.headerKey)
: tab.header)
(this.isOpen(index) ? 'Collapse' : 'Expand') + ' ' + header
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ export interface Tab {
* Identifies the index of the tab to set attributes by.
*/
id?: number;
/**
* Disables the tabindex on the border element so that the border
* of the tab can no longer be focused.
*/
disableBorderFocus?: boolean;
}

export interface TabConfig {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@
(click)="block($event)"
>
<div class="list-header">
<h4>
{{ 'productList.filterBy.label' | cxTranslate }}
</h4>
<h4>{{ 'productList.filterBy.label' | cxTranslate }}</h4>
<button
type="button"
class="close"
Expand All @@ -26,22 +24,43 @@ <h4>
Here we'd like to introduce configurable facet components,
either by using specific configuration or generic sproutlets
-->
<cx-facet
*ngFor="let facet of facets"
#facetRef
[facet]="facet"
[class.expanded]="isExpanded(facet) | async"
[class.collapsed]="isCollapsed(facet) | async"
role="group"
attr.aria-label="{{
'productFacetNavigation.ariaLabelItemsAvailable'
| cxTranslate
: {
name: facet.name,
count: facet?.values?.length,
}
}}"
></cx-facet>
<ng-container *cxFeature="'a11yTabComponent'">
<cx-tab [tabs$]="tabs$" [config]="tabConfig" *ngIf="tabs$ | async"></cx-tab>

<ng-template #facetsRef *ngFor="let facet of facets">
<cx-facet
[facet]="facet"
role="group"
attr.aria-label="{{
'productFacetNavigation.ariaLabelItemsAvailable'
| cxTranslate
: {
name: facet.name,
count: facet?.values?.length
}
}}"
></cx-facet>
</ng-template>
</ng-container>

<ng-container *cxFeature="'!a11yTabComponent'">
<cx-facet
*ngFor="let facet of facets"
#facetRef
[facet]="facet"
[class.expanded]="isExpanded(facet) | async"
[class.collapsed]="isCollapsed(facet) | async"
role="group"
attr.aria-label="{{
'productFacetNavigation.ariaLabelItemsAvailable'
| cxTranslate
: {
name: facet.name,
count: facet?.values?.length
}
}}"
></cx-facet>
</ng-container>

<ng-container *cxFeature="'a11yFacetsDialogFocusHandling'">
<div *ngIf="isDialog" class="cx-facet-list-footer">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,15 @@ import {
Renderer2,
ViewChild,
inject,
AfterViewInit,
ViewChildren,
QueryList,
TemplateRef,
} from '@angular/core';
import { Facet, FeatureConfigService } from '@spartacus/core';
import { Observable, Subscription } from 'rxjs';
import { map } from 'rxjs/operators';
import { Facet, FeatureConfigService, useFeatureStyles } from '@spartacus/core';
import { Tab, TabConfig, TAB_MODE } from '../../../../content/tab/tab.model';
import { BehaviorSubject, Observable, Subscription } from 'rxjs';
import { filter, map, take } from 'rxjs/operators';
import {
FocusConfig,
KeyboardFocusService,
Expand All @@ -36,7 +41,7 @@ import { FacetService } from '../services/facet.service';
templateUrl: './facet-list.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class FacetListComponent implements OnInit, OnDestroy {
export class FacetListComponent implements OnInit, OnDestroy, AfterViewInit {
protected subscriptions = new Subscription();
private _isDialog: boolean;

Expand Down Expand Up @@ -73,6 +78,16 @@ export class FacetListComponent implements OnInit, OnDestroy {
autofocus: 'cx-facet > button',
};

tabConfig: TabConfig = {
label: 'Product Facets',
mode: TAB_MODE.ACCORDIAN,
openTabs: [0],
};

tabs$: BehaviorSubject<Tab[]> = new BehaviorSubject<Tab[]>([]);

@ViewChildren('facetsRef') facetsRef: QueryList<TemplateRef<any>>;

@HostListener('click') handleClick() {
this.close();
}
Expand All @@ -85,13 +100,45 @@ export class FacetListComponent implements OnInit, OnDestroy {
protected facetService: FacetService,
protected elementRef: ElementRef,
protected renderer: Renderer2
) {}
) {
useFeatureStyles('a11yTabComponent');
}

ngOnInit(): void {
// TODO: (CXSPA-7321) - Remove feature flag next major release
if (this.featureConfigService?.isEnabled('a11yFacetsDialogFocusHandling')) {
this.enableFocusHandlingOnFacetListChanges();
}

// Required to load facets when initial load in side panel.
this.updateTabs();
}

ngAfterViewInit(): void {
// Required to render facets when opening filters dialog.
this.updateTabs();

// Required to render facet changes (ie. select facet, etc)
this.subscriptions.add(
this.facetsRef.changes
.pipe(filter((changes) => !!changes))
.subscribe(() => {
this.updateTabs();
})
);
}

updateTabs(): void {
this.facetList$.pipe(take(1)).subscribe((list) => {
const facets = list.facets;
const tabs = facets.map((facet, i) => ({
header: facet.name,
content: this.facetsRef?.get(i),
disableBorderFocus: true,
}));

this.tabs$.next(tabs);
});
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { FeaturesConfigModule, I18nModule } from '@spartacus/core';
import { TabModule } from '../../../../content/tab/tab.module';
import { KeyboardFocusModule } from '../../../../../layout/a11y/keyboard-focus/keyboard-focus.module';
import { IconModule } from '../../../../misc/icon/icon.module';
import { FacetModule } from '../facet/facet.module';
Expand All @@ -20,6 +21,7 @@ import { FacetListComponent } from './facet-list.component';
FacetModule,
KeyboardFocusModule,
FeaturesConfigModule,
TabModule,
],
declarations: [FacetListComponent],
exports: [FacetListComponent],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
'productFacetNavigation.filterBy.name' | cxTranslate: { name: facet.name }
"
[cxFocus]="{ key: facet.name }"
*cxFeature="'!a11yTabComponent'"
>
{{ facet.name }}
<cx-icon
Expand All @@ -31,7 +32,6 @@
routerLink="./"
[queryParams]="getLinkParams(value)"
class="value"
[tabindex]="isFacetKeyboardNavigationEnabled ? -1 : 0"
[class.selected]="value.selected"
[cxFocus]="{ key: value.name }"
(keydown)="onKeydown($event)"
Expand All @@ -57,7 +57,6 @@
"
#facetValue
routerLink="./"
[tabindex]="isFacetKeyboardNavigationEnabled ? -1 : 0"
[queryParams]="getLinkParams(value)"
class="value"
[class.selected]="value.selected"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,9 +140,6 @@ export class FacetComponent implements AfterViewInit {
case 'ArrowLeft':
this.onArrowLeft(event);
break;
case 'ArrowRight':
this.onArrowRight(event);
break;
case 'ArrowDown':
this.onArrowDown(event, targetIndex);
break;
Expand All @@ -152,34 +149,21 @@ export class FacetComponent implements AfterViewInit {
}
}

onArrowRight(event: Event): void {
if (!this.isExpanded) {
this.toggleGroup(event as UIEvent);
}
}

onArrowLeft(event: Event): void {
if (this.isExpanded) {
this.toggleGroup(event as UIEvent);
this.facetHeader.nativeElement.focus();
}
event.preventDefault();
const parent: any =
this.values.get(0)?.nativeElement.parentElement?.parentElement
?.parentElement?.parentElement?.previousElementSibling;
parent?.click();
}

onArrowDown(event: Event, targetIndex: number): void {
if (this.isExpanded) {
event.preventDefault();
if (event.target === this.facetHeader.nativeElement) {
this.values?.first?.nativeElement.focus();
return;
}
this.values.get(targetIndex + 1)?.nativeElement.focus();
}
event.preventDefault();
this.values.get(targetIndex + 1)?.nativeElement.focus();
}

onArrowUp(event: Event, targetIndex: number): void {
if (this.isExpanded) {
event.preventDefault();
this.values.get(targetIndex - 1)?.nativeElement.focus();
}
event.preventDefault();
this.values.get(targetIndex - 1)?.nativeElement.focus();
}
}
Loading
Loading