Last active
January 24, 2020 16:21
-
-
Save Hagith/eab5f5c547b6fa852c789011b8cf08db to your computer and use it in GitHub Desktop.
ngx-bootstrap-dropdown-popper - https://stackblitz.com/edit/angular-msq1rb
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$dropdown-bg: #fff; | |
$dropdown-arrow-size: 6px; | |
.dropdown-menu { | |
// reset basic dropdown position for Popper.js | |
&[x-placement^='top'], | |
&[x-placement^='right'], | |
&[x-placement^='bottom'], | |
&[x-placement^='left'] { | |
top: auto; | |
right: auto; | |
bottom: auto; | |
left: auto; | |
} | |
.dropdown-menu-arrow { | |
position: absolute; | |
width: $dropdown-arrow-size * 2; | |
height: $dropdown-arrow-size; | |
&:before, | |
&:after { | |
position: absolute; | |
border-style: solid; | |
content: ''; | |
} | |
&:before { | |
top: 0; | |
left: 0; | |
border-width: $dropdown-arrow-size + 1; | |
border-color: rgba(0, 0, 0, 0.2); | |
} | |
&:after { | |
top: 1px; | |
left: 1px; | |
border-width: $dropdown-arrow-size; | |
border-color: $dropdown-bg; | |
} | |
} | |
&.with-arrow { | |
&[x-placement^='top'] { | |
margin-bottom: $dropdown-arrow-size; | |
.dropdown-menu-arrow { | |
bottom: -$dropdown-arrow-size - 1; | |
&:before, | |
&:after { | |
border-bottom-width: 0; | |
border-right-color: transparent; | |
border-bottom-color: transparent; | |
border-left-color: transparent; | |
} | |
&:after { | |
top: -1px; | |
} | |
} | |
} | |
&[x-placement^='bottom'] { | |
margin-top: $dropdown-arrow-size; | |
.dropdown-menu-arrow { | |
top: -$dropdown-arrow-size - 1; | |
&:before, | |
&:after { | |
border-top-width: 0; | |
border-top-color: transparent; | |
border-right-color: transparent; | |
border-left-color: transparent; | |
} | |
} | |
} | |
&[x-placement^='left'] { | |
margin-right: $dropdown-arrow-size; | |
.dropdown-menu-arrow { | |
width: $dropdown-arrow-size; | |
height: $dropdown-arrow-size * 2; | |
right: -$dropdown-arrow-size - 1; | |
&:before, | |
&:after { | |
border-right-width: 0; | |
border-top-color: transparent; | |
border-right-color: transparent; | |
border-bottom-color: transparent; | |
} | |
&:before { | |
border-left-color: rgba(0, 0, 0, 0.12); | |
} | |
&:after { | |
left: -1px; | |
} | |
} | |
} | |
&[x-placement^='right'] { | |
margin-left: $dropdown-arrow-size; | |
.dropdown-menu-arrow { | |
width: $dropdown-arrow-size; | |
height: $dropdown-arrow-size * 2; | |
left: -$dropdown-arrow-size - 1; | |
&:before, | |
&:after { | |
border-left-width: 0; | |
border-top-color: transparent; | |
border-bottom-color: transparent; | |
border-left-color: transparent; | |
} | |
&:before { | |
border-right-color: rgba(0, 0, 0, 0.12); | |
} | |
&:after { | |
right: -1px; | |
} | |
} | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Directive, ElementRef, EventEmitter, HostListener, Input } from '@angular/core'; | |
@Directive({ | |
selector: '[sysDropdownToggle]', | |
exportAs: 'sysDropdownToggle', | |
host: { | |
'[class.dropdown-toggle]': 'caret', | |
'[attr.aria-haspopup]': 'true', | |
'[attr.aria-expanded]': 'isOpen', | |
}, | |
}) | |
export class SysDropdownToggleDirective { | |
@Input() caret = true; | |
isOpen = false; | |
toggleClick = new EventEmitter<boolean>(); | |
constructor(public host: ElementRef<HTMLElement>) {} | |
get element() { | |
return this.host.nativeElement; | |
} | |
@HostListener('click', ['$event']) onClick(event: MouseEvent): void { | |
event.stopPropagation(); | |
this.isOpen = !this.isOpen; | |
this.toggleClick.emit(true); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { | |
AfterContentInit, | |
ChangeDetectorRef, | |
ContentChild, | |
Directive, | |
EventEmitter, | |
Input, | |
OnDestroy, | |
Output, | |
Renderer2, | |
} from '@angular/core'; | |
import Popper, { Placement, PopperOptions } from 'popper.js'; | |
import { Subject } from 'rxjs'; | |
import { takeUntil } from 'rxjs/operators'; | |
import { SysDropdownMenuDirective } from './dropdown-menu.directive'; | |
import { SysDropdownToggleDirective } from './dropdown-toggle.directive'; | |
@Directive({ | |
selector: '[sysDropdown]', | |
exportAs: 'sysDropdown', | |
host: { | |
class: 'dropdown', | |
'[class.show]': 'open', | |
'[class.open]': 'open', | |
}, | |
}) | |
export class SysDropdownDirective implements AfterContentInit, OnDestroy { | |
@Input() placement: Placement = 'bottom-end'; | |
@Input() container: string; | |
@Input() withArrow = false; | |
@Input() insideClick = false; | |
@Output() shown = new EventEmitter<void>(); | |
@Output() hidden = new EventEmitter<void>(); | |
open = false; | |
@ContentChild(SysDropdownToggleDirective, { static: false }) | |
private _toggle: SysDropdownToggleDirective; | |
@ContentChild(SysDropdownMenuDirective, { static: false }) | |
private _menu: SysDropdownMenuDirective; | |
private _popper: Popper; | |
private _listeners: (() => void)[] = []; | |
private _destroy: Subject<boolean> = new Subject<boolean>(); | |
constructor(private _renderer: Renderer2, private _changeDetectorRef: ChangeDetectorRef) {} | |
ngAfterContentInit(): void { | |
this._toggle.toggleClick.pipe(takeUntil(this._destroy)).subscribe(() => this.toggle()); | |
} | |
ngOnDestroy(): void { | |
this._destroy.next(true); | |
this._destroy.complete(); | |
} | |
show() { | |
const menu = this._menu.create(this.withArrow, this.container); | |
const popperOptions: PopperOptions = { | |
placement: this.placement, | |
modifiers: {}, | |
}; | |
if (this.withArrow) { | |
popperOptions.modifiers.arrow = { | |
element: this._menu.arrow, | |
}; | |
} | |
this._changeDetectorRef.detectChanges(); // prevents positioning issue | |
this._popper = new Popper(this._toggle.element, menu, popperOptions); | |
this._listen(); | |
this.shown.emit(); | |
} | |
hide() { | |
this._popper.destroy(); | |
this._menu.destroy(); | |
this._dispose(); | |
this.hidden.emit(); | |
} | |
toggle() { | |
this.open = !this.open; | |
this.open ? this.show() : this.hide(); | |
} | |
private _listen() { | |
const documentListener = this._renderer.listen('document', 'click', (event: MouseEvent) => { | |
if (!this._toggle.element.contains(event.target as Element)) { | |
this.toggle(); | |
this._changeDetectorRef.markForCheck(); | |
} | |
}); | |
this._listeners.push(documentListener); | |
const escListener = this._renderer.listen(this._menu.element, 'keyup.esc', () => { | |
this.toggle(); | |
this._changeDetectorRef.markForCheck(); | |
}); | |
this._listeners.push(escListener); | |
if (this.insideClick) { | |
const insideListener = this._renderer.listen(this._menu.element, 'click', (e: MouseEvent) => | |
e.stopPropagation() | |
); | |
this._listeners.push(insideListener); | |
} | |
} | |
private _dispose() { | |
this._listeners.forEach(dispose => dispose()); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { CommonModule } from '@angular/common'; | |
import { NgModule } from '@angular/core'; | |
import { SysDropdownMenuDirective } from './dropdown-menu.directive'; | |
import { SysDropdownToggleDirective } from './dropdown-toggle.directive'; | |
import { SysDropdownDirective } from './dropdown.directive'; | |
@NgModule({ | |
imports: [CommonModule], | |
exports: [SysDropdownDirective, SysDropdownToggleDirective, SysDropdownMenuDirective], | |
declarations: [SysDropdownDirective, SysDropdownToggleDirective, SysDropdownMenuDirective], | |
}) | |
export class SysDropdownModule {} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment