Skip to content

Commit

Permalink
[HXCS-1479] Core breadcrumbs component (#8695)
Browse files Browse the repository at this point in the history
* Moving breadcrumb component from Hyland UI to ADF and renaming selectors and entities with proper prefix

* Cleaning up a bit the breadcumbs

* Stabilising breadcrumbs and adding storibook

* Fix change requests
  • Loading branch information
popovicsandras committed Jun 27, 2023
1 parent bce1f34 commit 037dce0
Show file tree
Hide file tree
Showing 12 changed files with 440 additions and 0 deletions.
22 changes: 22 additions & 0 deletions lib/core/src/lib/breadcrumb/_breadcrumb.theme.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
@use 'sass:map';
@use '@angular/material' as mat;

@mixin adf-breadcrumb-theme($theme) {
$config: mat.get-color-config($theme);
$foreground-palette: map.get($config, foreground);
$primary-palette: map.get($config, primary);
$text-color: mat.get-color-from-palette($foreground-palette, text);

.adf-breadcrumb__show-all-button-icon--rotate {
color: mat.get-color-from-palette($primary-palette, 500);
}

.adf-breadcrumb .adf-breadcrumb__item-wrapper:last-child a {
text-decoration: none;
color: $text-color;
}

.adf-breadcrumb .adf-breadcrumb__item-wrapper:last-child a:hover {
text-decoration: none;
}
}
75 changes: 75 additions & 0 deletions lib/core/src/lib/breadcrumb/_stories/breadcrumb.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*!
* @license
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { Meta, moduleMetadata, Story } from '@storybook/angular';
import { MatButtonModule } from '@angular/material/button';
import { MatMenuModule } from '@angular/material/menu';
import { MatIconModule } from '@angular/material/icon';
import { BreadcrumbComponent } from '../components/breadcrumb/breadcrumb.component';
import { BreadcrumbItemComponent } from '../components/breadcrumb-item/breadcrumb-item.component';
import { DemoBreadcrumbComponent } from './demo-breadcrumb.component';
import { CoreStoryModule } from '../../testing/core.story.module';

// https://stackoverflow.com/a/58210459/8820824
type NonFunctionPropertyNames<T> = {[K in keyof T]: T[K] extends () => any ? never : K}[keyof T];
type NonFunctionProperties<T> = Pick<T, NonFunctionPropertyNames<T>>;
type StoryWithoutFunction<T> = NonFunctionProperties<Story<T>>;

function storybookCopyStory<T>( story: Story<T>, annotations?: StoryWithoutFunction<T> ): Story<T> {
const cloned = story.bind({});
return Object.assign(cloned, annotations);
}

const meta: Meta = {
title: 'Core/Breadcrumb',
decorators: [
moduleMetadata({
imports: [
CoreStoryModule,
BreadcrumbComponent,
BreadcrumbItemComponent,
MatButtonModule,
MatMenuModule,
MatIconModule
]
})
],
args: {
compact: false,
showBreadcrumbItemWithMenu: false
},
argTypes: {
compact: {control: 'boolean'},
showBreadcrumbItemWithMenu: {control: 'boolean'}
}
};
export default meta;

export const breadcrumb: Story = args => ({
component: DemoBreadcrumbComponent,
props: args
});

export const compact = storybookCopyStory(breadcrumb);
compact.args = {
compact: true
};

export const withMenu = storybookCopyStory(breadcrumb);
withMenu.args = {
showBreadcrumbItemWithMenu: true
};
63 changes: 63 additions & 0 deletions lib/core/src/lib/breadcrumb/_stories/demo-breadcrumb.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*!
* @license
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import {Component} from '@angular/core';

@Component({
selector: 'adf-demo-breadcrumb',
template: `
<adf-breadcrumb [compact]="compact">
<adf-breadcrumb-item>
<a href="/">Home</a>
</adf-breadcrumb-item>
<adf-breadcrumb-item>
<a href="https://www.alfresco.com/">Alfresco</a>
</adf-breadcrumb-item>
<adf-breadcrumb-item>
<a href="https://www.alfresco.com">External Link 1</a>
</adf-breadcrumb-item>
<adf-breadcrumb-item>
<a href="https://www.alfresco.com/">External Link 2</a>
</adf-breadcrumb-item>
<adf-breadcrumb-item>
<a href="https://www.alfresco.com/">External Link 3</a>
</adf-breadcrumb-item>
<adf-breadcrumb-item *ngIf="showBreadcrumbItemWithMenu" aria-current="location" aria-haspopup="true" >
<div>
Current Page
<button mat-icon-button [matMenuTriggerFor]="menu" aria-label="Menu">
<mat-icon>menu_open</mat-icon>
</button>
<mat-menu #menu="matMenu">
<button mat-menu-item>Menu Item 1</button>
<button mat-menu-item>Menu Item 2</button>
</mat-menu>
</div>
</adf-breadcrumb-item>
</adf-breadcrumb>
`
})
export class DemoBreadcrumbComponent {
compact = false;
showBreadcrumbItemWithMenu = false;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*!
* @license
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { Component, TemplateRef, ViewChild } from '@angular/core';

@Component({
standalone: true,
selector: 'adf-breadcrumb-item',
template: `
<ng-template #breadcrumbItemTemplate>
<ng-content></ng-content>
</ng-template>
`
})
export class BreadcrumbItemComponent {
@ViewChild('breadcrumbItemTemplate', { static: true })
templateRef!: TemplateRef<any>;
}
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<ng-container>
<nav class="adf-breadcrumb" [class.adf-breadcrumb--compact]="compact" [attr.aria-label]="'CORE.BREADCRUMBS.TITLE' | translate" >
<ol>
<ng-container *ngFor="let breadcrumbTemplate of selectedBreadcrumbs; last as last">
<li adf-breadcrumb-focus class="adf-breadcrumb__item-wrapper">
<ng-container *ngTemplateOutlet="breadcrumbTemplate"></ng-container>
<div *ngIf="!last" class="adf-breadcrumb__chevron" [class.adf-breadcrumb__chevron-before--compact]="compact" ></div>
</li>

<li *ngIf="!last && compact === true" class="adf-breadcrumb__show-all-button-wrapper">
<button
mat-icon-button
(click)="toggleCompact()"
color="primary"
[matTooltip]="'CORE.BREADCRUMBS.SHOWALL' | translate"
matTooltipClass="adf-tooltip"
[attr.aria-label]="'CORE.BREADCRUMBS.SHOWALL' | translate"
>
<mat-icon class="adf-breadcrumb__show-all-button-icon--rotate">more_vert</mat-icon >
</button>
<div class="adf-breadcrumb__chevron" [class.adf-breadcrumb__chevron-after--compact]="compact" ></div>
</li>
</ng-container>
</ol>
</nav>
</ng-container>
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
ol {
margin: 0;
padding: 0;
display: flex;
flex-wrap: wrap;
min-height: 40px;
}

.adf-breadcrumb__item-wrapper {
display: flex;
align-items: center;
}

.adf-breadcrumb__chevron {
background-image: url("breadcrumb-chevron.svg");
background-repeat: no-repeat;
background-position: center;
width: 5px;
height: 8px;
margin: 0 8px;

:host-context([dir="rtl"]) & {
transform: scaleX(-1);
}
}

.adf-breadcrumb__chevron-before--compact {
margin: 0 4px 0 8px;

:host-context([dir="rtl"]) & {
margin: 0 8px 0 4px;
}
}

.adf-breadcrumb__chevron-after--compact {
margin: 0 8px 0 4px;

:host-context([dir="rtl"]) & {
margin: 0 4px 0 8px;
}
}

.adf-breadcrumb__show-all-button-wrapper {
display: flex;
align-items: center;
}

.adf-breadcrumb__show-all-button-icon--rotate {
transform: rotate(90deg);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*!
* @license
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { AfterContentInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChildren, EventEmitter, Input, OnChanges, Output, QueryList, SimpleChanges, TemplateRef, ViewChildren } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatTooltipModule } from '@angular/material/tooltip';
import { map, startWith } from 'rxjs/operators';
import { TranslateModule } from '@ngx-translate/core';

import { BreadcrumbFocusDirective } from '../../directives/breadcrumb-focus.directive';
import { BreadcrumbItemComponent } from '../breadcrumb-item/breadcrumb-item.component';

@Component({
standalone: true,
selector: 'adf-breadcrumb',
templateUrl: './breadcrumb.component.html',
styleUrls: ['./breadcrumb.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [ CommonModule, MatIconModule, TranslateModule, MatButtonModule, MatTooltipModule ]
})
export class BreadcrumbComponent implements AfterContentInit, OnChanges {
private _breadcrumbTemplateRefs: Array<TemplateRef<unknown>> = [];

@Input()
compact = false;

@Output()
compactChange: EventEmitter<boolean> = new EventEmitter();

@ViewChildren(BreadcrumbFocusDirective)
breadcrumbFocusItems!: QueryList<BreadcrumbFocusDirective>;

@ContentChildren(BreadcrumbItemComponent)
breadcrumbItems!: QueryList<BreadcrumbItemComponent>;

selectedBreadcrumbs: Array<TemplateRef<unknown>> = [];

constructor(private cdr: ChangeDetectorRef) {}

ngAfterContentInit() {
this.breadcrumbItems.changes
.pipe(
startWith(this.breadcrumbItems),
map((breadcrumbItems: QueryList<BreadcrumbItemComponent>) =>
this.mapToTemplateRefs(breadcrumbItems)
)
)
.subscribe((templateRefs) => {
this._breadcrumbTemplateRefs = templateRefs;
this.setBreadcrumbs(templateRefs);
});
}

ngOnChanges(changes: SimpleChanges): void {
if (changes.compact) {
this.setBreadcrumbs(this._breadcrumbTemplateRefs);
}
}

toggleCompact(compact = false) {
this.compact = compact;
this.setBreadcrumbs(this._breadcrumbTemplateRefs);
this.compactChange.emit(this.compact);
if (!compact) {
this.breadcrumbFocusItems.get(1)?.focusOnFirstFocusableElement();
}
}

private setBreadcrumbs(breadcrumbs: Array<TemplateRef<unknown>>) {
this.selectedBreadcrumbs =
this.compact && breadcrumbs.length > 2
? [breadcrumbs[0], breadcrumbs[breadcrumbs.length - 1]]
: [...breadcrumbs];
this.cdr.detectChanges();
}

private mapToTemplateRefs( breadcrumbItems: QueryList<BreadcrumbItemComponent> ) {
return breadcrumbItems
.toArray()
.map((breadcrumbItem) => breadcrumbItem.templateRef);
}
}

0 comments on commit 037dce0

Please sign in to comment.