feat(breadcrumbs): ionCollapsedClick event payload now contains references to collapsed breadcrumb elements (#23611)

resolves #23552
This commit is contained in:
Liam DeBeasi
2021-07-13 11:21:36 -04:00
committed by GitHub
parent 8f2c4f73db
commit 9ce57d2efb
10 changed files with 170 additions and 134 deletions

View File

@ -55,7 +55,10 @@ export class Breadcrumbs implements ComponentInterface {
@Listen('collapsedClick')
onCollapsedClick(ev: CustomEvent) {
this.ionCollapsedClick.emit(ev.detail)
const breadcrumbs = this.getBreadcrumbs();
const collapsedBreadcrumbs = breadcrumbs.filter(breadcrumb => breadcrumb.collapsed);
this.ionCollapsedClick.emit({ ...ev.detail, collapsedBreadcrumbs });
}
@Watch('maxItems')

View File

@ -349,6 +349,9 @@ export class BreadcrumbsExample {
async presentPopover(ev: any) {
const popover = await this.popoverController.create({
component: PopoverComponent,
componentProps: {
collapsedBreadcrumbs: ev.detail.collapsedBreadcrumbs
},
event: ev
});
await popover.present();
@ -356,13 +359,23 @@ export class BreadcrumbsExample {
}
```
```html
<ion-content>
<ion-list>
<ion-item *ngFor="let breadcrumb of collapsedBreadcrumbs" [href]="breadcrumb.href">
<ion-label>{{ breadcrumb.textContent }}</ion-label>
</ion-item>
</ion-list>
</ion-content>
```
```typescript
import { Component } from '@angular/core';
import { Component, Input } from '@angular/core';
@Component({
selector: 'popover-component',
})
export class PopoverComponent {
@Input() collapsedBreadcrumbs: HTMLElement[] = [];
constructor() {}
@ -699,21 +712,18 @@ class ListPopover extends HTMLElement {
}
connectedCallback() {
let breadcrumbTemplate = ``;
this.collapsedBreadcrumbs.forEach(breadcrumb => {
breadcrumbTemplate += `
<ion-item href="${breadcrumb.href}">
<ion-label>${breadcrumb.textContent}</ion-label>
</ion-item>
`;
})
this.innerHTML = `
<ion-content>
<ion-list>
<ion-item href="#">
<ion-label>Home</ion-label>
</ion-item>
<ion-item href="#electronics">
<ion-label>Electronics</ion-label>
</ion-item>
<ion-item href="#photography">
<ion-label>Photography</ion-label>
</ion-item>
<ion-item href="#cameras">
<ion-label>Cameras</ion-label>
</ion-item>
${breadcrumbTemplate}
</ion-list>
</ion-content>
`;
@ -725,6 +735,9 @@ customElements.define('list-popover', ListPopover);
async function presentPopover(ev) {
const popover = Object.assign(document.createElement('ion-popover'), {
component: 'list-popover',
componentProps: {
collapsedBreadcrumbs: ev.detail.collapsedBreadcrumbs
},
event: ev
});
document.body.appendChild(popover);
@ -1071,21 +1084,15 @@ import { IonBreadcrumb, IonBreadcrumbs, IonContent, IonItem, IonLabel, IonList,
const PopoverList: React.FC<{
onHide: () => void;
}> = ({ onHide }) => (
collapsedBreadcrumbs: HTMLElement[]
}> = ({ onHide, collapsedBreadcrumbs }) => (
<IonContent>
<IonList>
<IonItem href="#">
<IonLabel>Home</IonLabel>
</IonItem>
<IonItem href="#electronics">
<IonLabel>Electronics</IonLabel>
</IonItem>
<IonItem href="#photography">
<IonLabel>Photography</IonLabel>
</IonItem>
<IonItem href="#cameras">
<IonLabel>Cameras</IonLabel>
</IonItem>
{collapsedBreadcrumbs.map(breadcrumb => (
<IonItem href={breadcrumb.href}>
<IonLabel>{breadcrumb.textContent}</IonLabel>
</IonItem>
))}
</IonList>
</IonContent>
);
@ -1510,6 +1517,9 @@ export class BreadcrumbsExample {
async presentPopover(ev: any) {
const popover = await popoverController.create({
component: 'list-popover',
componentProps: {
collapsedBreadcrumbs: ev.detail.collapsedBreadcrumbs
},
event: ev
});
await popover.present();
@ -1543,29 +1553,24 @@ export class BreadcrumbsExample {
```
```tsx
import { Component, h } from '@stencil/core';
import { Component, h, Prop } from '@stencil/core';
@Component({
tag: 'list-popover',
styleUrl: 'list-popover.css',
})
export class ListPopover {
@Prop() collapsedBreadcrumbs: HTMLElement[] = [];
render() {
return [
<ion-content>
<ion-list>
<ion-item href="#">
<ion-label>Home</ion-label>
</ion-item>
<ion-item href="#electronics">
<ion-label>Electronics</ion-label>
</ion-item>
<ion-item href="#photography">
<ion-label>Photography</ion-label>
</ion-item>
<ion-item href="#cameras">
<ion-label>Cameras</ion-label>
</ion-item>
{this.collapsedBreadcrumbs.map(breadcrumb => (
<ion-item href={breadcrumb.href}>
<ion-label>{breadcrumb.textContent}</ion-label>
</ion-item>
))}
</ion-list>
</ion-content>
];
@ -1990,6 +1995,9 @@ export default defineComponent({
async presentPopover(ev: Event) {
const popover = await popoverController.create({
component: ListPopover,
componentProps: {
collapsedBreadcrumbs: ev.detail.collapsedBreadcrumbs
},
event: ev
});
await popover.present();
@ -2003,17 +2011,8 @@ export default defineComponent({
<template>
<ion-content>
<ion-list>
<ion-item href="#">
<ion-label>Home</ion-label>
</ion-item>
<ion-item href="#electronics">
<ion-label>Electronics</ion-label>
</ion-item>
<ion-item href="#photography">
<ion-label>Photography</ion-label>
</ion-item>
<ion-item href="#cameras">
<ion-label>Cameras</ion-label>
<ion-item v-for="breadcrumb in $props.collapsedBreadcrumbs" :href="breadcrumb.href">
<ion-label>{{ breadcrumb.textContent }}</ion-label>
</ion-item>
</ion-list>
</ion-content>
@ -2025,6 +2024,9 @@ import { defineComponent } from 'vue';
export default defineComponent({
name: 'ListPopover',
props: {
collapsedBreadcrumbs: { type: Array, default: [] }
},
components: { IonContent, IonItem, IonLabel, IonList }
});
</script>

View File

@ -18,6 +18,13 @@
<ion-title>Breadcrumbs - Basic</ion-title>
</ion-toolbar>
<ion-toolbar>
<ion-breadcrumbs max-items="2" items-before-collapse="1" items-after-collapse="1">
<ion-breadcrumb>First</ion-breadcrumb>
<ion-breadcrumb>Second</ion-breadcrumb>
<ion-breadcrumb>Third</ion-breadcrumb>
<ion-breadcrumb>Fourth</ion-breadcrumb>
<ion-breadcrumb>Fifth</ion-breadcrumb>
</ion-breadcrumbs>
<ion-breadcrumbs>
<ion-breadcrumb href="#">
Home
@ -281,27 +288,13 @@
<h1>Breadcrumbs: collapsed / popover on click</h1>
<ion-breadcrumbs id="popoverOnClick" max-items="4" items-before-collapse="0" items-after-collapse="3">
<ion-breadcrumb href="#">
Home
</ion-breadcrumb>
<ion-breadcrumb href="#electronics">
Cameras & Camcorders
</ion-breadcrumb>
<ion-breadcrumb href="#digital-camera-accessories">
Digital Camera Accessories
</ion-breadcrumb>
<ion-breadcrumb href="#camera-lenses">
Camera Lenses
</ion-breadcrumb>
<ion-breadcrumb href="#dslr-lenses">
DSLR Lenses
</ion-breadcrumb>
<ion-breadcrumb href="#prime-lenses">
Prime Lenses
</ion-breadcrumb>
<ion-breadcrumb>
Product Info
</ion-breadcrumb>
<ion-breadcrumb href="#">Home</ion-breadcrumb>
<ion-breadcrumb href="#electronics">Cameras & Camcorders</ion-breadcrumb>
<ion-breadcrumb href="#digital-camera-accessories">Digital Camera Accessories</ion-breadcrumb>
<ion-breadcrumb href="#camera-lenses">Camera Lenses</ion-breadcrumb>
<ion-breadcrumb href="#dslr-lenses">DSLR Lenses</ion-breadcrumb>
<ion-breadcrumb href="#prime-lenses">Prime Lenses</ion-breadcrumb>
<ion-breadcrumb>Product Info</ion-breadcrumb>
</ion-breadcrumbs>
<hr>
@ -456,21 +449,20 @@
}
connectedCallback() {
let template = '';
this.collapsedBreadcrumbs.forEach(breadcrumb => {
template += `
<ion-item href="${breadcrumb.href}">
<ion-label>${breadcrumb.textContent}</ion-label>
</ion-item>
`;
});
this.innerHTML = `
<ion-content>
<ion-list>
<ion-item href="#">
<ion-label>Home</ion-label>
</ion-item>
<ion-item href="#electronics">
<ion-label>Cameras & Camcorders</ion-label>
</ion-item>
<ion-item href="#digital-camera-accessories">
<ion-label>Digital Camera Accessories</ion-label>
</ion-item>
<ion-item href="#camera-lenses">
<ion-label>Camera Lenses</ion-label>
</ion-item>
${template}
</ion-list>
</ion-content>
`;
@ -483,6 +475,7 @@
console.log('present ev', ev);
const popover = Object.assign(document.createElement('ion-popover'), {
component: 'list-popover',
componentProps: ev.detail,
event: ev,
});
document.body.appendChild(popover);

View File

@ -0,0 +1,35 @@
import { newSpecPage } from '@stencil/core/testing';
import { Breadcrumbs } from '../breadcrumbs.tsx';
import { Breadcrumb } from '../../breadcrumb/breadcrumb.tsx';
it('should correctly provide the collapsed breadcrumbs in the event payload', async () => {
const page = await newSpecPage({
components: [Breadcrumbs, Breadcrumb],
html: `
<ion-breadcrumbs max-items="2" items-before-collapse="1" items-after-collapse="1">
<ion-breadcrumb>First</ion-breadcrumb>
<ion-breadcrumb>Second</ion-breadcrumb>
<ion-breadcrumb>Third</ion-breadcrumb>
<ion-breadcrumb>Fourth</ion-breadcrumb>
<ion-breadcrumb>Fifth</ion-breadcrumb>
</ion-breadcrumbs>
`
});
const onCollapsedClick = jest.fn((ev) => ev);
const breadcrumbs = page.body.querySelector('ion-breadcrumbs');
const breadcrumb = page.body.querySelectorAll('ion-breadcrumb');
breadcrumbs.addEventListener('ionCollapsedClick', onCollapsedClick);
const event = new CustomEvent('collapsedClick');
breadcrumbs.dispatchEvent(event);
expect(onCollapsedClick).toHaveBeenCalledTimes(1);
const collapsedBreadcrumbs = onCollapsedClick.mock.calls[0][0].detail.collapsedBreadcrumbs;
expect(collapsedBreadcrumbs.length).toEqual(3);
expect(collapsedBreadcrumbs[0]).toBe(breadcrumb[1]);
expect(collapsedBreadcrumbs[1]).toBe(breadcrumb[2]);
expect(collapsedBreadcrumbs[2]).toBe(breadcrumb[3]);
});

View File

@ -337,6 +337,9 @@ export class BreadcrumbsExample {
async presentPopover(ev: any) {
const popover = await this.popoverController.create({
component: PopoverComponent,
componentProps: {
collapsedBreadcrumbs: ev.detail.collapsedBreadcrumbs
},
event: ev
});
await popover.present();
@ -344,13 +347,23 @@ export class BreadcrumbsExample {
}
```
```html
<ion-content>
<ion-list>
<ion-item *ngFor="let breadcrumb of collapsedBreadcrumbs" [href]="breadcrumb.href">
<ion-label>{{ breadcrumb.textContent }}</ion-label>
</ion-item>
</ion-list>
</ion-content>
```
```typescript
import { Component } from '@angular/core';
import { Component, Input } from '@angular/core';
@Component({
selector: 'popover-component',
})
export class PopoverComponent {
@Input() collapsedBreadcrumbs: HTMLElement[] = [];
constructor() {}

View File

@ -325,21 +325,18 @@ class ListPopover extends HTMLElement {
}
connectedCallback() {
let breadcrumbTemplate = ``;
this.collapsedBreadcrumbs.forEach(breadcrumb => {
breadcrumbTemplate += `
<ion-item href="${breadcrumb.href}">
<ion-label>${breadcrumb.textContent}</ion-label>
</ion-item>
`;
})
this.innerHTML = `
<ion-content>
<ion-list>
<ion-item href="#">
<ion-label>Home</ion-label>
</ion-item>
<ion-item href="#electronics">
<ion-label>Electronics</ion-label>
</ion-item>
<ion-item href="#photography">
<ion-label>Photography</ion-label>
</ion-item>
<ion-item href="#cameras">
<ion-label>Cameras</ion-label>
</ion-item>
${breadcrumbTemplate}
</ion-list>
</ion-content>
`;
@ -351,6 +348,9 @@ customElements.define('list-popover', ListPopover);
async function presentPopover(ev) {
const popover = Object.assign(document.createElement('ion-popover'), {
component: 'list-popover',
componentProps: {
collapsedBreadcrumbs: ev.detail.collapsedBreadcrumbs
},
event: ev
});
document.body.appendChild(popover);

View File

@ -333,21 +333,15 @@ import { IonBreadcrumb, IonBreadcrumbs, IonContent, IonItem, IonLabel, IonList,
const PopoverList: React.FC<{
onHide: () => void;
}> = ({ onHide }) => (
collapsedBreadcrumbs: HTMLElement[]
}> = ({ onHide, collapsedBreadcrumbs }) => (
<IonContent>
<IonList>
<IonItem href="#">
<IonLabel>Home</IonLabel>
</IonItem>
<IonItem href="#electronics">
<IonLabel>Electronics</IonLabel>
</IonItem>
<IonItem href="#photography">
<IonLabel>Photography</IonLabel>
</IonItem>
<IonItem href="#cameras">
<IonLabel>Cameras</IonLabel>
</IonItem>
{collapsedBreadcrumbs.map(breadcrumb => (
<IonItem href={breadcrumb.href}>
<IonLabel>{breadcrumb.textContent}</IonLabel>
</IonItem>
))}
</IonList>
</IonContent>
);

View File

@ -387,6 +387,9 @@ export class BreadcrumbsExample {
async presentPopover(ev: any) {
const popover = await popoverController.create({
component: 'list-popover',
componentProps: {
collapsedBreadcrumbs: ev.detail.collapsedBreadcrumbs
},
event: ev
});
await popover.present();
@ -420,29 +423,24 @@ export class BreadcrumbsExample {
```
```tsx
import { Component, h } from '@stencil/core';
import { Component, h, Prop } from '@stencil/core';
@Component({
tag: 'list-popover',
styleUrl: 'list-popover.css',
})
export class ListPopover {
@Prop() collapsedBreadcrumbs: HTMLElement[] = [];
render() {
return [
<ion-content>
<ion-list>
<ion-item href="#">
<ion-label>Home</ion-label>
</ion-item>
<ion-item href="#electronics">
<ion-label>Electronics</ion-label>
</ion-item>
<ion-item href="#photography">
<ion-label>Photography</ion-label>
</ion-item>
<ion-item href="#cameras">
<ion-label>Cameras</ion-label>
</ion-item>
{this.collapsedBreadcrumbs.map(breadcrumb => (
<ion-item href={breadcrumb.href}>
<ion-label>{breadcrumb.textContent}</ion-label>
</ion-item>
))}
</ion-list>
</ion-content>
];

View File

@ -412,6 +412,9 @@ export default defineComponent({
async presentPopover(ev: Event) {
const popover = await popoverController.create({
component: ListPopover,
componentProps: {
collapsedBreadcrumbs: ev.detail.collapsedBreadcrumbs
},
event: ev
});
await popover.present();
@ -425,17 +428,8 @@ export default defineComponent({
<template>
<ion-content>
<ion-list>
<ion-item href="#">
<ion-label>Home</ion-label>
</ion-item>
<ion-item href="#electronics">
<ion-label>Electronics</ion-label>
</ion-item>
<ion-item href="#photography">
<ion-label>Photography</ion-label>
</ion-item>
<ion-item href="#cameras">
<ion-label>Cameras</ion-label>
<ion-item v-for="breadcrumb in $props.collapsedBreadcrumbs" :href="breadcrumb.href">
<ion-label>{{ breadcrumb.textContent }}</ion-label>
</ion-item>
</ion-list>
</ion-content>
@ -447,6 +441,9 @@ import { defineComponent } from 'vue';
export default defineComponent({
name: 'ListPopover',
props: {
collapsedBreadcrumbs: { type: Array, default: [] }
},
components: { IonContent, IonItem, IonLabel, IonList }
});
</script>