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(core): migrate breadcrumbs component #8402

Merged
merged 8 commits into from
Jul 25, 2022
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
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
Expand Up @@ -20,15 +20,3 @@
<fd-breadcrumb-href-example></fd-breadcrumb-href-example>
</component-example>
<code-example [exampleFiles]="breadcrumbHrefHtml"></code-example>

<fd-docs-section-title id="responsive" componentName="breadcrumb"> Responsive Breadcrumbs </fd-docs-section-title>
<description>
The breadcrumb will automatically refer to its parent element to know whether to show breadcrumbs or to collapse
them into the overflow menu. You can provide an HTMLElement to the [containerElement] input to set your own
container element. Note that the responsiveness feature will not function properly if the containerElement or parent
element have a set fixed width.
</description>
<component-example>
<fd-breadcrumb-responsive-example></fd-breadcrumb-responsive-example>
</component-example>
<code-example [exampleFiles]="breadcrumbResponsiveHtml"></code-example>
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Component } from '@angular/core';

import breadcrumbHrefExample from '!./examples/breadcrumb-href-example.component.html?raw';
import breadcrumbResponsiveExample from '!./examples/breadcrumb-responsive-example.component.html?raw';
import breadcrumbRouterLinkExample from '!./examples/breadcrumb-routerLink-example.component.html?raw';
import { ExampleFile } from '../../../documentation/core-helpers/code-example/example-file';

Expand All @@ -25,12 +24,4 @@ export class BreadcrumbDocsComponent {
fileName: 'fd-breadcrumb-href-example'
}
];

breadcrumbResponsiveHtml: ExampleFile[] = [
{
language: 'html',
code: breadcrumbResponsiveExample,
fileName: 'fd-breadcrumb-responsive-example'
}
];
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { ApiComponent } from '../../../documentation/core-helpers/api/api.compon
import { API_FILES } from '../../api-files';
import {
BreadcrumbHrefExampleComponent,
BreadcrumbResponsiveExampleComponent,
BreadcrumbRouterLinkExampleComponent
} from './examples/breadcrumb-examples.component';
import { BreadcrumbHeaderComponent } from './breadcrumb-header/breadcrumb-header.component';
Expand All @@ -31,8 +30,7 @@ const routes: Routes = [
BreadcrumbDocsComponent,
BreadcrumbHeaderComponent,
BreadcrumbHrefExampleComponent,
BreadcrumbRouterLinkExampleComponent,
BreadcrumbResponsiveExampleComponent
BreadcrumbRouterLinkExampleComponent
],
providers: [moduleDeprecationsProvider(DeprecatedBreadcrumbsCompactDirective)]
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,3 @@ export class BreadcrumbRouterLinkExampleComponent {
]
})
export class BreadcrumbHrefExampleComponent {}

@Component({
selector: 'fd-breadcrumb-responsive-example',
templateUrl: './breadcrumb-responsive-example.component.html'
})
export class BreadcrumbResponsiveExampleComponent {}

This file was deleted.

2 changes: 1 addition & 1 deletion e2e/wdio/core/pages/dynamic-page.po.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export class DynamicPagePo extends CoreBaseComponentPo {
flexibleColumn = '.fd-flexible-column-layout__column ';
article = '.fd-dynamic-page-section-example';
breadcrumbLink = '.fd-dynamic-page__breadcrumb-wrapper a';
currentBreadcrumbLink = '.fd-dynamic-page__breadcrumb-wrapper fd-breadcrumb-item:last-child span';
currentBreadcrumbLink = '.fd-dynamic-page__breadcrumb-wrapper .fd-overflow-layout__item--last span';

open(): void {
super.open(this.url);
Expand Down
82 changes: 56 additions & 26 deletions libs/core/src/lib/breadcrumb/breadcrumb-item.component.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { DomPortal } from '@angular/cdk/portal';
import {
AfterViewInit,
ChangeDetectorRef,
ChangeDetectionStrategy,
Component,
ContentChild,
ElementRef,
forwardRef,
Renderer2
ViewEncapsulation
} from '@angular/core';
import { LinkComponent } from '@fundamental-ngx/core/link';
import { DomPortal } from '@angular/cdk/portal';

/**
* Breadcrumb item directive. Must have child breadcrumb link directives.
Expand All @@ -21,54 +21,84 @@ import { DomPortal } from '@angular/cdk/portal';
*/
@Component({
selector: 'fd-breadcrumb-item',
template: '<div style="display: inline"><ng-content></ng-content></div>',
template: '<ng-content></ng-content>',
host: {
class: 'fd-breadcrumb__item'
}
},
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class BreadcrumbItemComponent implements AfterViewInit {
/** @hidden */
get elementRef(): ElementRef<HTMLElement> {
return this._elementRef;
}

/** @hidden */
@ContentChild(forwardRef(() => LinkComponent))
breadcrumbLink: LinkComponent;

/** @hidden */
get width(): number {
return this._elementRef.nativeElement.getBoundingClientRect().width;
}

/** In case there is no link in Item and breadcrumb item is non-interactive, we move whole item content to menu item title */
breadcrumbItemPortal: DomPortal<Element>;

/** When breadcrumb item has link in it, we are moving link content to menu item title */
linkContentPortal: DomPortal;

constructor(
private _elementRef: ElementRef<HTMLElement>,
private renderer2: Renderer2,
private _cdR: ChangeDetectorRef
) {}
/**
* Breadcrumb item dom portal.
*/
portal: DomPortal;

/** @hidden */
private _attached = false;

/** @hidden */
constructor(public readonly elementRef: ElementRef<HTMLElement>) {}

/** @hidden */
get needsClickProxy(): boolean {
get _needsClickProxy(): boolean {
return (
!!this.breadcrumbLink?.elementRef().nativeElement.getAttribute('href') || !!this.breadcrumbLink.routerLink
);
}

show = (): void => this.renderer2.setStyle(this._elementRef.nativeElement, 'display', 'inline-block');
hide = (): void => this.renderer2.setStyle(this._elementRef.nativeElement, 'display', 'none');

/** @hidden */
ngAfterViewInit(): void {
if (this.breadcrumbLink) {
this._attach();
}

/**
* Sets breadcrumb item dom portal.
*/
setPortal(): void {
if (!this.portal) {
this.portal = new DomPortal(this.elementRef);
}
}

/** @hidden */
_detach(): void {
if (!this._attached) {
return;
}

if (this.linkContentPortal?.isAttached) {
this.linkContentPortal?.detach();
}

if (this.breadcrumbItemPortal?.isAttached) {
this.breadcrumbItemPortal?.detach();
}

this._attached = false;
}

/** @hidden */
_attach(): void {
if (this._attached) {
return;
}

if (this.breadcrumbLink && this.breadcrumbLink.contentSpan) {
this.linkContentPortal = new DomPortal<HTMLElement>(this.breadcrumbLink.contentSpan.nativeElement);
}

this.breadcrumbItemPortal = new DomPortal(this.elementRef.nativeElement.firstElementChild as Element);
this._cdR.detectChanges();
this._attached = true;
}
}
114 changes: 68 additions & 46 deletions libs/core/src/lib/breadcrumb/breadcrumb.component.html
Original file line number Diff line number Diff line change
@@ -1,52 +1,74 @@
<fd-menu #menu [closeOnEscapeKey]="true" [focusAutoCapture]="true" [placement]="_placement$ | async">
<ng-container *ngFor="let breadcrumbItem of _collapsedBreadcrumbItems">
<li fd-menu-item [disabled]="breadcrumbItem.breadcrumbLink ? breadcrumbItem.breadcrumbLink.disabled : false">
<fd-overflow-layout
[reverseHiddenItems]="reverse"
showMorePosition="left"
[enableKeyboardNavigation]="false"
(visibleItemsCount)="_onVisibleItemsCountChange($event)"
(hiddenItemsCount)="_onHiddenItemsCountChange($event)"
>
<ng-container *ngFor="let breadcrumb of _items">
<div
*fdOverflowItemRef="breadcrumb; let hidden"
fdOverflowLayoutItem
(hiddenChange)="_onHiddenChange($event, breadcrumb)"
>
<ng-template [cdkPortalOutlet]="breadcrumb.portal"></ng-template>
</div>
</ng-container>
<ng-container *fdOverflowExpand="let breadcrumbs; items: _items">
<fd-menu #menu [closeOnEscapeKey]="true" [focusAutoCapture]="true" [placement]="_placement$ | async">
<ng-container *ngFor="let breadcrumbItem of breadcrumbs">
<li
fd-menu-item
[disabled]="
breadcrumbItem.item.breadcrumbLink ? breadcrumbItem.item.breadcrumbLink.disabled : false
"
>
<a
fd-menu-interactive
(click)="itemClicked(breadcrumbItem.item, $event)"
(keydown.enter)="itemClicked(breadcrumbItem.item, $event)"
(keydown.space)="itemClicked(breadcrumbItem.item, $event)"
>
<ng-container *ngIf="breadcrumbItem?.item.breadcrumbLink; else portalContent">
<ng-container *ngIf="breadcrumbItem.item.breadcrumbLink._prefixIconName">
<fd-menu-addon
position="before"
[glyph]="breadcrumbItem.item.breadcrumbLink._prefixIconName"
></fd-menu-addon>
</ng-container>
<span fd-menu-title>
<ng-container [cdkPortalOutlet]="breadcrumbItem.item.linkContentPortal"></ng-container>
</span>
<ng-container *ngIf="breadcrumbItem.item.breadcrumbLink._postfixIconName">
<fd-menu-addon
[glyph]="breadcrumbItem.item.breadcrumbLink._postfixIconName"
></fd-menu-addon>
</ng-container>
</ng-container>
<ng-template #portalContent>
<span fd-menu-title>
<ng-container
[cdkPortalOutlet]="breadcrumbItem.item.breadcrumbItemPortal"
></ng-container>
</span>
</ng-template>
</a>
</li>
</ng-container>
</fd-menu>
<span class="fd-breadcrumb__item" *ngIf="breadcrumbs.length > 0" [fdMenuTrigger]="menu">
<a
fd-menu-interactive
(click)="itemClicked(breadcrumbItem, $event)"
(keydown.enter)="itemClicked(breadcrumbItem, $event)"
(keydown.space)="itemClicked(breadcrumbItem, $event)"
fd-link
tabindex="0"
class="fd-breadcrumb__collapsed"
(keydown.enter)="_keyDownHandle($event)"
(keydown.space)="_keyDownHandle($event)"
>
<ng-container *ngIf="breadcrumbItem?.breadcrumbLink; else portalContent">
<ng-container *ngIf="breadcrumbItem.breadcrumbLink._prefixIconName">
<fd-menu-addon
position="before"
[glyph]="breadcrumbItem.breadcrumbLink._prefixIconName"
></fd-menu-addon>
</ng-container>
<span fd-menu-title>
<ng-container [cdkPortalOutlet]="breadcrumbItem.linkContentPortal"></ng-container>
</span>
<ng-container *ngIf="breadcrumbItem.breadcrumbLink._postfixIconName">
<fd-menu-addon [glyph]="breadcrumbItem.breadcrumbLink._postfixIconName"></fd-menu-addon>
</ng-container>
</ng-container>
<ng-template #portalContent>
<span fd-menu-title>
<ng-container [cdkPortalOutlet]="breadcrumbItem.breadcrumbItemPortal"></ng-container>
</span>
</ng-template>
<fd-icon glyph="slim-arrow-down"></fd-icon>
</a>
</li>
</span>
</ng-container>
</fd-menu>

<span
class="fd-breadcrumb__item"
*ngIf="_collapsedBreadcrumbItems.length"
[fdMenuTrigger]="menu"
#overflowBreadcrumbsContainer
>
<a
fd-link
tabindex="0"
class="fd-breadcrumb__collapsed"
(keydown.enter)="_keyDownHandle($event)"
(keydown.space)="_keyDownHandle($event)"
>
...
<fd-icon glyph="slim-arrow-down"></fd-icon>
</a>
</span>
</fd-overflow-layout>

<ng-content></ng-content>
10 changes: 9 additions & 1 deletion libs/core/src/lib/breadcrumb/breadcrumb.component.scss
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
@import '~fundamental-styles/dist/breadcrumb';

.fd-breadcrumb {
display: inline-block;
display: flex;
white-space: nowrap;

.fd-breadcrumb__collapsed {
cursor: pointer;
}
}

.fd-breadcrumb__item:last-child::after {
content: '/';
}

.fd-overflow-layout__item--last .fd-breadcrumb__item::after {
content: none;
}
Loading