Skip to content

Commit

Permalink
feat(accordion): demo examples
Browse files Browse the repository at this point in the history
  • Loading branch information
ValentinNelu authored and quentinderoubaix committed Sep 13, 2023
1 parent 25c56e4 commit b71fa6d
Show file tree
Hide file tree
Showing 21 changed files with 819 additions and 63 deletions.
132 changes: 132 additions & 0 deletions angular/demo/src/app/samples/accordion/customHeaders.route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import {AgnosUIAngularModule} from '@agnos-ui/angular';
import {Component} from '@angular/core';
import {NgIf} from '@angular/common';
import BODY from '!raw-loader!@agnos-ui/common/samples/accordion/body.txt';

@Component({
standalone: true,
imports: [AgnosUIAngularModule, NgIf],
template: `
<div auAccordion #accordion="auAccordion">
<div au-accordion-item>
<ng-template auAccordionItemStructure let-state="state" let-widget="widget">
<div
class="{{ state.itemHeaderClass }} accordion-button accordion-header custom-header justify-content-between"
[class.collapsed]="state.itemCollapsed"
role="heading"
aria-level="2"
>
<p class="m-0">First panel - {{ state.itemCollapsed ? 'collapsed' : 'opened' }}</p>
<button
type="button"
id="{{ state.itemId }}-toggle"
(click)="widget.actions.click()"
class="btn btn-link p-0 {{ state.itemButtonClass }}"
[class.collapsed]="state.itemCollapsed"
[disabled]="state.itemDisabled"
attr.aria-controls="{{ state.itemId }}-collapse"
[attr.aria-disabled]="state.itemDisabled"
[attr.aria-expanded]="!state.itemCollapsed"
>
Toggle first
</button>
</div>
<div
*ngIf="state!.shouldBeInDOM"
[auUse]="widget!.directives.collapseDirective"
attr.aria-labelledby="{{ state!.itemId }}-toggle"
id="{{ state!.itemId }}-collapse"
class="accordion-collapse {{ state!.itemCollapseClass }}"
>
<div class="accordion-body {{ state!.itemBodyClass }}">
{{ BODY }}
</div>
</div>
</ng-template>
</div>
<div au-accordion-item>
<ng-template auAccordionItemStructure let-state="state" let-widget="widget">
<div
class="{{ state.itemHeaderClass }} accordion-button accordion-header custom-header justify-content-between"
[class.collapsed]="state.itemCollapsed"
role="heading"
aria-level="2"
>
<p class="m-0">Second panel</p>
<div>
<button
type="button"
class="btn btn-sm btn-outline-primary me-2 {{ state.itemButtonClass }}"
[class.collapsed]="state.itemCollapsed"
id="{{ state.itemId }}-toggle"
(click)="widget.actions.click()"
[disabled]="state.itemDisabled"
[attr.aria-disabled]="state.itemDisabled"
[attr.aria-expanded]="!state.itemCollapsed"
attr.aria-controls="{{ state.itemId }}-collapse"
>
Toggle second
</button>
<button type="button" class="btn btn-sm btn-outline-secondary me-2" (click)="thirdDisabled = !thirdDisabled">
{{ thirdDisabled ? 'En' : 'Dis' }}able third
</button>
<button type="button" class="btn btn-sm btn-outline-danger me-2" (click)="accordion.api.collapseAll()">Collapse all</button>
</div>
</div>
<div
*ngIf="state!.shouldBeInDOM"
[auUse]="widget!.directives.collapseDirective"
attr.aria-labelledby="{{ state!.itemId }}-toggle"
id="{{ state!.itemId }}-collapse"
class="accordion-collapse {{ state!.itemCollapseClass }}"
>
<div class="accordion-body {{ state!.itemBodyClass }}">
{{ BODY }}
</div>
</div>
</ng-template>
</div>
<div au-accordion-item [itemDisabled]="thirdDisabled">
<ng-template auAccordionItemStructure let-state="state" let-widget="widget">
<div
class="{{ state.itemHeaderClass }} accordion-button accordion-header custom-header justify-content-between"
[class.collapsed]="state.itemCollapsed"
role="heading"
aria-level="2"
>
<button
type="button"
class="p-0 btn btn-link container-fluid text-start {{ state.itemButtonClass }}"
[class.collapsed]="state.itemCollapsed"
id="{{ state.itemId }}-toggle"
(click)="widget.actions.click()"
[disabled]="state.itemDisabled"
[attr.aria-disabled]="state.itemDisabled"
attr.aria-controls="{{ state.itemId }}-collapse"
[attr.aria-expanded]="!state.itemCollapsed"
>
Third panel
</button>
<p *ngIf="thirdDisabled" class="text-muted m-0 small">[I'm&nbsp;disabled]</p>
</div>
<div
*ngIf="state!.shouldBeInDOM"
[auUse]="widget!.directives.collapseDirective"
attr.aria-labelledby="{{ state!.itemId }}-toggle"
id="{{ state!.itemId }}-collapse"
class="accordion-collapse {{ state!.itemCollapseClass }}"
>
<div class="accordion-body {{ state!.itemBodyClass }}">
{{ BODY }}
</div>
</div>
</ng-template>
</div>
</div>
`,
styles: ["@import '@agnos-ui/common/samples/accordion/custom.scss';"],
})
export default class AccordionComponent {
thirdDisabled = false;
BODY = BODY;
}
29 changes: 7 additions & 22 deletions angular/demo/src/app/samples/accordion/default.route.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {AgnosUIAngularModule} from '@agnos-ui/angular';
import {Component} from '@angular/core';
import BODY from '!raw-loader!@agnos-ui/common/samples/accordion/body.txt';

@Component({
standalone: true,
Expand All @@ -8,37 +9,21 @@ import {Component} from '@angular/core';
<div auAccordion>
<div au-accordion-item [itemCollapsed]="false">
<ng-template auAccordionItemHeader>Simple</ng-template>
<ng-template auAccordionItemBody
>Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat
skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid
single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea
proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably
haven't heard of them accusamus labore sustainable VHS.
</ng-template>
<ng-template auAccordionItemBody>{{ BODY }} </ng-template>
</div>
<div au-accordion-item>
<ng-template auAccordionItemHeader
><span>&#9733; <b>Fancy</b> title &#9733;</span></ng-template
>
<ng-template auAccordionItemBody
>Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat
skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid
single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea
proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably
haven't heard of them accusamus labore sustainable VHS.
</ng-template>
<ng-template auAccordionItemBody>{{ BODY }} </ng-template>
</div>
<div au-accordion-item [itemDisabled]="true">
<ng-template auAccordionItemHeader>Disabled</ng-template>
<ng-template auAccordionItemBody
>Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat
skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid
single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea
proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably
haven't heard of them accusamus labore sustainable VHS.
</ng-template>
<ng-template auAccordionItemBody>{{ BODY }} </ng-template>
</div>
</div>
`,
})
export default class AccordionComponent {}
export default class AccordionComponent {
BODY = BODY;
}
29 changes: 29 additions & 0 deletions angular/demo/src/app/samples/accordion/togglePanels.route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import {AgnosUIAngularModule} from '@agnos-ui/angular';
import {Component} from '@angular/core';
import {NgFor} from '@angular/common';
import BODY from '!raw-loader!@agnos-ui/common/samples/accordion/body.txt';

@Component({
standalone: true,
imports: [AgnosUIAngularModule, NgFor],
template: `
<div auAccordion #accordion="auAccordion">
<div au-accordion-item [itemId]="'first'">
<ng-template auAccordionItemHeader>First panel</ng-template>
<ng-template auAccordionItemBody>{{ BODY }} </ng-template>
</div>
<div au-accordion-item [itemId]="'second'" #itemTwo>
<ng-template auAccordionItemHeader>Second panel</ng-template>
<ng-template auAccordionItemBody>{{ BODY }} </ng-template>
</div>
</div>
<hr />
<button class="btn btn-sm btn-outline-primary me-2" (click)="accordion.api.toggle('first')">Toggle first</button>
<button class="btn btn-sm btn-outline-primary me-2" (click)="itemTwo.api.toggle()">Toggle second</button>
<button class="btn btn-sm btn-outline-primary me-2" (click)="accordion.api.expandAll()">Expand all</button>
<button class="btn btn-sm btn-outline-primary me-2" (click)="accordion.api.collapseAll()">Collapse all</button>
`,
})
export default class AccordionComponent {
BODY = BODY;
}
4 changes: 2 additions & 2 deletions angular/lib/src/lib/accordion/accordion.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,10 @@ export class AccordionItemStructureDirective {
export class AccordionItemDefaultSlotsComponent {
@ViewChild('structure', {static: true}) structure: TemplateRef<AccordionItemContext>;
}
export const accordionItemDefaultslotItemStructure = new ComponentTemplate(AccordionItemDefaultSlotsComponent, 'structure');
export const accordionItemDefaultSlotItemStructure = new ComponentTemplate(AccordionItemDefaultSlotsComponent, 'structure');

const defaultConfig: Partial<AccordionItemProps> = {
slotItemStructure: accordionItemDefaultslotItemStructure,
slotItemStructure: accordionItemDefaultSlotItemStructure,
};

@Component({
Expand Down
9 changes: 8 additions & 1 deletion angular/lib/src/lib/agnos-ui-angular.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,13 @@ import {SelectComponent} from './select/select.component';
import {UseDirective} from './transition/use.directive';
import {SlotDirective} from './slot.directive';
import {AlertComponent} from './alert/alert.component';
import {AccordionDirective, AccordionItemComponent, AccordionHeaderDirective, AccordionBodyDirective} from './accordion/accordion.component';
import {
AccordionDirective,
AccordionItemComponent,
AccordionHeaderDirective,
AccordionBodyDirective,
AccordionItemStructureDirective,
} from './accordion/accordion.component';

/* istanbul ignore next */
const components = [
Expand Down Expand Up @@ -50,6 +56,7 @@ const components = [
AccordionItemComponent,
AccordionHeaderDirective,
AccordionBodyDirective,
AccordionItemStructureDirective,
];

@NgModule({
Expand Down
1 change: 1 addition & 0 deletions common/samples/accordion/body.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS.
3 changes: 3 additions & 0 deletions common/samples/accordion/custom.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.custom-header::after {
content: none !important;
}
6 changes: 4 additions & 2 deletions demo/scripts/includeSamples.plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {readFile} from 'fs/promises';

const samplePrefix = '@agnos-ui/samples/';
const rawSampleSuffix = '?raw&sample';
const commonImport = /^(!raw-loader!)?@agnos-ui\/common\/samples\/([^?]*)(\?raw)?$/;

const importRegExp = /import([^;]+from)?\s*['"]([^'"]+)['"]\s*;/g;
const findDependencies = (fileContent: string) => {
Expand Down Expand Up @@ -54,8 +55,9 @@ export const includeSamples = (): Plugin => {
const dependencyParts = dependency.split('/');
if (dependencyParts[0] === '.') {
await addFile(framework, path.basename(dependency), path.join(directory, dependency));
} else if (dependency.startsWith('@agnos-ui/common/samples')) {
await addFile(framework, path.basename(dependency), path.join(__dirname, '..', '..', 'common', dependency.substring(17)));
} else if (dependency.match(commonImport)) {
const cleanedDependency = dependency.replace(commonImport, './$2');
await addFile(framework, path.basename(cleanedDependency), path.join(__dirname, '..', '..', 'common', 'samples', cleanedDependency));
} else {
// TODO: check that the dependency is valid and included in package.json
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
<script lang="ts">
import sampleDefault from '@agnos-ui/samples/accordion/default';
import togglePanels from '@agnos-ui/samples/accordion/togglePanels';
import customHeaders from '@agnos-ui/samples/accordion/customHeaders';
import Sample from '$lib/layout/Sample.svelte';
import Section from '$lib/layout/Section.svelte';
</script>

<Section label="Default" id="default" level={2}>
<Sample title="Default example" sample={sampleDefault} height={395} />
</Section>
<Section label="Toggle panels" id="togglePanels" level={2}>
<Sample title="Toggle panels" sample={togglePanels} height={395} />
</Section>
<Section label="Custom Headers" id="customHeaders" level={2}>
<Sample title="Custom Headers" sample={customHeaders} height={395} />
</Section>

<Section label="Accessibility" id="accessibility" level={2}>
<p>
Expand Down
54 changes: 52 additions & 2 deletions e2e/accordion/accordion.e2e-spec.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import {expect, test} from '@playwright/test';
import {AccordionPO} from '@agnos-ui/page-objects';
import {AccordionTogglePanels} from '../demo-po/accordion.po';

type PromiseValue<T> = T extends Promise<infer U> ? U : never;
type State = PromiseValue<ReturnType<AccordionPO['state']>>;

test.describe.parallel(`Accordion tests`, () => {
test(`Default accordion behaviour`, async ({page}) => {
const accordionPO = new AccordionPO(page, 0);
await page.goto('#/accordion/default');
await accordionPO.locatorRoot.waitFor();
const accordionPO = new AccordionPO(page, 0);

const itemsIds = await Promise.all((await accordionPO.locatorAccordionItems.all()).map((item) => item.getAttribute('id')));
const expectedState: State = {
Expand Down Expand Up @@ -59,4 +59,54 @@ test.describe.parallel(`Accordion tests`, () => {
expectedState.items[1].expanded = 'true';
expect(await accordionPO.state()).toEqual(expectedState);
});
test(`Toggle Panels`, async ({page}) => {
const accordionDemoPO = new AccordionTogglePanels(page);
await page.goto('#/accordion/togglepanels');
const accordionPO = new AccordionPO(page, 0);
await accordionDemoPO.locatorRoot.waitFor();
const itemsIds = await Promise.all((await accordionPO.locatorAccordionItems.all()).map((item) => item.getAttribute('id')));
const expectedState: State = {
items: [
{
classes: ['accordion-item'],
id: itemsIds[0]!,
isInDOM: true,
collapseId: `${itemsIds[0]!}-collapse`,
buttonId: `${itemsIds[0]!}-toggle`,
expanded: 'false',
disabled: 'false',
labeledBy: `${itemsIds[0]!}-toggle`,
buttonControls: `${itemsIds[0]!}-collapse`,
},
{
classes: ['accordion-item'],
id: itemsIds[1]!,
isInDOM: true,
collapseId: `${itemsIds[1]!}-collapse`,
buttonId: `${itemsIds[1]!}-toggle`,
expanded: 'false',
disabled: 'false',
labeledBy: `${itemsIds[1]!}-toggle`,
buttonControls: `${itemsIds[1]!}-collapse`,
},
],
rootClasses: ['accordion'],
};
expect(await accordionPO.state()).toEqual(expectedState);
await accordionDemoPO.locatorToggleFirst().click();
expectedState.items[0].expanded = 'true';
expect(await accordionPO.state()).toEqual(expectedState);
await accordionDemoPO.locatorToggleFirst().click();
await accordionDemoPO.locatorToggleSecond().click();
expectedState.items[0].expanded = 'false';
expectedState.items[1].expanded = 'true';
expect(await accordionPO.state()).toEqual(expectedState);
await accordionDemoPO.locatorExpandAll().click();
expectedState.items[0].expanded = 'true';
expect(await accordionPO.state()).toEqual(expectedState);
await accordionDemoPO.locatorCollapseAll().click();
expectedState.items[0].expanded = 'false';
expectedState.items[1].expanded = 'false';
expect(await accordionPO.state()).toEqual(expectedState);
});
});
17 changes: 17 additions & 0 deletions e2e/demo-po/accordion.po.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,20 @@ export class AccordionDemoPO extends BasePO {
return '.container';
}
}

export class AccordionTogglePanels extends AccordionDemoPO {
locatorToggleFirst() {
return this.locatorRoot.getByText('Toggle first');
}
locatorToggleSecond() {
return this.locatorRoot.getByText('Toggle second');
}
locatorExpandAll() {
return this.locatorRoot.getByText('Expand all');
}
locatorCollapseAll() {
return this.locatorRoot.getByText('Collapse all');
}
}

export class AccordionCustomHeaders extends AccordionDemoPO {}
Loading

0 comments on commit b71fa6d

Please sign in to comment.