Skip to content

Commit

Permalink
fix(menu): height calculation (#621)
Browse files Browse the repository at this point in the history
  • Loading branch information
yggg authored and nnixaa committed Aug 13, 2018
1 parent 7058a88 commit 7542d5e
Show file tree
Hide file tree
Showing 5 changed files with 228 additions and 139 deletions.
4 changes: 2 additions & 2 deletions src/framework/theme/components/menu/menu-item.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@
<ul *ngIf="menuItem.children"
[class.collapsed]="!(menuItem.children && menuItem.expanded)"
[class.expanded]="menuItem.expanded"
class="menu-items"
[style.max-height.px]="maxHeight">
[@toggle]="toggleState"
class="menu-items">
<ng-container *ngFor="let item of menuItem.children">
<li nbMenuItem *ngIf="!item.hidden"
[menuItem]="item"
Expand Down
1 change: 0 additions & 1 deletion src/framework/theme/components/menu/menu.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
.menu-item > .menu-items {
list-style-type: none;
overflow: hidden;
transition: max-height 0.3s ease-in;
}

.menu-item a {
Expand Down
98 changes: 35 additions & 63 deletions src/framework/theme/components/menu/menu.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,87 +12,65 @@ import {
OnInit,
OnDestroy,
HostBinding,
ViewChildren,
QueryList,
ElementRef,
AfterViewInit,
PLATFORM_ID,
Inject,
ChangeDetectorRef,
DoCheck,
} from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
import { Router, NavigationEnd } from '@angular/router';
import { BehaviorSubject } from 'rxjs';
import { takeWhile, filter } from 'rxjs/operators';

import { NbMenuInternalService, NbMenuItem, NbMenuService, NbMenuBag } from './menu.service';
import { convertToBoolProperty, getElementHeight } from '../helpers';
import { takeWhile, filter, map } from 'rxjs/operators';
import { NbMenuInternalService, NbMenuItem, NbMenuBag, NbMenuService } from './menu.service';
import { convertToBoolProperty } from '../helpers';
import { NB_WINDOW } from '../../theme.options';
import { animate, state, style, transition, trigger } from '@angular/animations';

function sumSubmenuHeight(item: NbMenuItem) {
return item.expanded
? (item.subMenuHeight || 0) + item.children.filter(c => c.children).reduce((acc, c) => acc + sumSubmenuHeight(c), 0)
: 0;
export enum NbToggleStates {
Expanded = 'expanded',
Collapsed = 'collapsed',
}

@Component({
// tslint:disable-next-line:component-selector
selector: '[nbMenuItem]',
templateUrl: './menu-item.component.html',
animations: [
trigger('toggle', [
state(NbToggleStates.Collapsed, style({ height: '0' })),
state(NbToggleStates.Expanded, style({ height: '*' })),
transition(`${NbToggleStates.Collapsed} <=> ${NbToggleStates.Expanded}`, animate(300)),
]),
],
})
export class NbMenuItemComponent implements AfterViewInit, OnDestroy {
export class NbMenuItemComponent implements DoCheck, AfterViewInit, OnDestroy {
@Input() menuItem = <NbMenuItem>null;

@Output() hoverItem = new EventEmitter<any>();
@Output() toggleSubMenu = new EventEmitter<any>();
@Output() selectItem = new EventEmitter<any>();
@Output() itemClick = new EventEmitter<any>();

private alive: boolean = true;
private alive = true;
toggleState: NbToggleStates;

@ViewChildren(NbMenuItemComponent, { read: ElementRef }) subMenu: QueryList<ElementRef>;
maxHeight: number = 0;
constructor(private menuService: NbMenuService) {}

constructor(
private menuService: NbMenuService,
@Inject(PLATFORM_ID) private platformId: Object,
private changeDetection: ChangeDetectorRef,
) { }
ngDoCheck() {
this.toggleState = this.menuItem.expanded ? NbToggleStates.Expanded : NbToggleStates.Collapsed;
}

ngAfterViewInit() {
this.subMenu.changes
.pipe(takeWhile(() => this.alive))
.subscribe(() => {
this.updateSubmenuHeight();
this.updateMaxHeight();
});

this.menuService.onSubmenuToggle()
.pipe(takeWhile(() => this.alive))
.subscribe(() => this.updateMaxHeight());

this.updateSubmenuHeight();
this.updateMaxHeight();
this.changeDetection.detectChanges();
.pipe(
takeWhile(() => this.alive),
filter(({ item }) => item === this.menuItem),
map(({ item }: NbMenuBag) => item.expanded),
)
.subscribe(isExpanded => this.toggleState = isExpanded ? NbToggleStates.Expanded : NbToggleStates.Collapsed);
}

ngOnDestroy() {
this.alive = false;
}

updateSubmenuHeight() {
if (isPlatformBrowser(this.platformId)) {
this.menuItem.subMenuHeight = this.subMenu.reduce(
(acc, c) => acc + getElementHeight(c.nativeElement),
0,
);
}
}

updateMaxHeight() {
this.maxHeight = sumSubmenuHeight(this.menuItem);
}

onToggleSubMenu(item: NbMenuItem) {
this.toggleSubMenu.emit(item);
}
Expand Down Expand Up @@ -235,6 +213,8 @@ export class NbMenuComponent implements OnInit, AfterViewInit, OnDestroy {
}

ngOnInit() {
this.menuInternalService.prepareItems(this.items);

this.menuInternalService
.onAddItem()
.pipe(
Expand Down Expand Up @@ -267,34 +247,27 @@ export class NbMenuComponent implements OnInit, AfterViewInit, OnDestroy {
takeWhile(() => this.alive),
filter((data: { tag: string }) => this.compareTag(data.tag)),
)
.subscribe((data: { tag: string }) => {
this.collapseAll();
});
.subscribe(() => this.collapseAll());

this.router.events
.pipe(
takeWhile(() => this.alive),
filter(event => event instanceof NavigationEnd),
)
.subscribe(() => {
this.menuInternalService.resetItems(this.items);
this.menuInternalService.updateSelection(this.items, this.tag, this.autoCollapseValue)
this.menuInternalService.selectFromUrl(this.items, this.tag, this.autoCollapseValue);
});

// TODO: this probably won't work if you pass items dynamically into items input
this.menuInternalService.prepareItems(this.items);
this.items.push(...this.menuInternalService.getItems());
}

ngAfterViewInit() {
setTimeout(() => this.menuInternalService.updateSelection(this.items, this.tag));
setTimeout(() => this.menuInternalService.selectFromUrl(this.items, this.tag, this.autoCollapseValue));
}

onAddItem(data: { tag: string; items: NbMenuItem[] }) {
this.items.push(...data.items);

this.menuInternalService.prepareItems(this.items);
this.menuInternalService.updateSelection(this.items, this.tag, this.autoCollapseValue);
this.menuInternalService.selectFromUrl(this.items, this.tag, this.autoCollapseValue);
}

onHoverItem(item: NbMenuItem) {
Expand All @@ -311,8 +284,7 @@ export class NbMenuComponent implements OnInit, AfterViewInit, OnDestroy {

// TODO: is not fired on page reload
onSelectItem(item: NbMenuItem) {
this.menuInternalService.resetItems(this.items);
this.menuInternalService.selectItem(item, this.tag);
this.menuInternalService.selectItem(item, this.items, this.autoCollapseValue, this.tag);
}

onItemClick(item: NbMenuItem) {
Expand Down
Loading

0 comments on commit 7542d5e

Please sign in to comment.