-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
248 additions
and
66 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { ConnectionPositionPair, OriginConnectionPosition, OverlayConnectionPosition } from '@angular/cdk/overlay'; | ||
|
||
export class OverlayConnectionPositionPair extends ConnectionPositionPair { | ||
public static parse(value: string): ConnectionPositionPair[] { | ||
const values = value.trim().split(','); | ||
const positions = new Array<ConnectionPositionPair>(); | ||
values.forEach(pos => { | ||
const poss = pos.trim().split(' '); | ||
if (poss.length !== 4) { | ||
throw new Error('Invalid positions property for DejaMenuComponent. String entry must be of type \'positions="start top end bottom"\''); | ||
} | ||
|
||
const originPosition = { | ||
originX: poss[0], | ||
originY: poss[1] | ||
} as OriginConnectionPosition; | ||
|
||
const overlayPosition = { | ||
overlayX: poss[2], | ||
overlayY: poss[3] | ||
} as OverlayConnectionPosition; | ||
|
||
positions.push(new OverlayConnectionPositionPair(originPosition, overlayPosition)); | ||
}); | ||
|
||
return positions; | ||
} | ||
} | ||
|
||
export const defaultConnectionPositionPair: ConnectionPositionPair[] = OverlayConnectionPositionPair.parse('start bottom start top,start top start bottom,end bottom end top,end top end bottom'); |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,2 @@ | ||
/* | ||
* Public API Surface of lib | ||
*/ | ||
|
||
export * from './example/example.service'; | ||
export * from './example/example.component'; | ||
export * from './overlay.component'; | ||
export * from './connection-position-pair'; |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
<ng-container *ngIf="overlayInfos$ | async as overlayInfos"> | ||
<ng-template #overlayCmp cdk-connected-overlay [cdkConnectedOverlayHasBackdrop]="hasBackdrop" [cdkConnectedOverlayBackdropClass]="overlayBackdropClass" [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlayOffsetY]="overlayInfos.offsetY" [cdkConnectedOverlayOffsetX]="overlayInfos.offsetX" [cdkConnectedOverlayOrigin]="overlayInfos.origin" (backdropClick)="close()" (detach)="close()" [cdkConnectedOverlayPositions]="positionPairs" [cdkConnectedOverlayWidth]="overlayInfos.width"> | ||
<ng-content></ng-content> | ||
</ng-template> | ||
</ng-container> |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
@media print { | ||
.ngx-overlay-container { | ||
display: none; | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,195 @@ | ||
import { BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion'; | ||
import { CdkConnectedOverlay, CdkOverlayOrigin, OverlayContainer, OverlayModule } from '@angular/cdk/overlay'; | ||
import { CommonModule } from '@angular/common'; | ||
import { ChangeDetectionStrategy, Component, ElementRef, Input, OnChanges, SimpleChanges, ViewChild, ViewEncapsulation } from '@angular/core'; | ||
import { MediaService } from '@hug/ngx-core'; | ||
import { BehaviorSubject, combineLatestWith, delay, distinctUntilChanged, EMPTY, map, mergeWith, Observable, of, ReplaySubject, shareReplay, startWith, Subject, switchMap } from 'rxjs'; | ||
|
||
import { defaultConnectionPositionPair, OverlayConnectionPositionPair } from './connection-position-pair'; | ||
|
||
export interface ShowParams { | ||
event?: MouseEvent; | ||
offsetX?: number; | ||
offsetY?: number; | ||
} | ||
|
||
interface OverlayInfos { | ||
offsetX: number; | ||
offsetY: number; | ||
origin: CdkOverlayOrigin; | ||
width: string; | ||
} | ||
|
||
@Component({ | ||
changeDetection: ChangeDetectionStrategy.OnPush, | ||
encapsulation: ViewEncapsulation.None, | ||
selector: 'overlay', | ||
styleUrls: ['./overlay.component.scss'], | ||
templateUrl: './overlay.component.html', | ||
standalone: true, | ||
imports: [ | ||
CommonModule, | ||
OverlayModule | ||
] | ||
}) | ||
export class OverlayComponent implements OnChanges { | ||
@Input() public ownerElement!: HTMLElement; | ||
|
||
@Input() public width!: string; | ||
|
||
@Input() public widthForMobile = '100%'; | ||
|
||
@Input() public overlayBackdropClass = 'cdk-overlay-transparent-backdrop'; | ||
|
||
@Input() public overlayContainerClass?: string; | ||
|
||
@Input() public isMobile?: BooleanInput; | ||
|
||
/** Overlay pane containing the options. */ | ||
@ViewChild(CdkConnectedOverlay, { static: true }) private overlay?: CdkConnectedOverlay; | ||
|
||
public readonly isVisible$: Observable<boolean>; | ||
|
||
protected overlayInfos$: Observable<OverlayInfos | undefined>; | ||
|
||
private show$ = new ReplaySubject<ShowParams>(1); | ||
private hide$ = new Subject<void>(); | ||
|
||
/** Renvoie une valeur qui indique si le dialog est affiché. */ | ||
private isMobileExt$ = new BehaviorSubject<boolean | undefined>(undefined); | ||
|
||
private _hasBackdrop = true; | ||
private ownerElement$ = new BehaviorSubject<HTMLElement | undefined>(undefined); | ||
|
||
@Input() public set hasBackdrop(value: BooleanInput) { | ||
this._hasBackdrop = coerceBooleanProperty(value); | ||
} | ||
|
||
public get hasBackdrop(): BooleanInput { | ||
return this._hasBackdrop; | ||
} | ||
|
||
private _positions = defaultConnectionPositionPair; | ||
private _positionsForMobile?: OverlayConnectionPositionPair[]; | ||
|
||
public constructor(private elementRef: ElementRef, private overlayContainer: OverlayContainer, mediaService: MediaService) { | ||
const containerElement = this.overlayContainer.getContainerElement(); | ||
containerElement.addEventListener('contextmenu', (event: Event) => { | ||
event.preventDefault(); | ||
return false; | ||
}); | ||
|
||
const isMobile$ = this.isMobileExt$.pipe( | ||
switchMap(isMobileExt => { | ||
if (isMobileExt !== undefined) { | ||
return of(isMobileExt); | ||
} | ||
|
||
return mediaService.isMobile$; | ||
}), | ||
startWith(false), | ||
shareReplay({ bufferSize: 1, refCount: false }) | ||
); | ||
|
||
this.overlayInfos$ = this.show$.pipe( | ||
mergeWith(this.hide$), | ||
switchMap(showParams => { | ||
if (!showParams) { | ||
return of(undefined); | ||
} | ||
|
||
containerElement.className = Array.from(containerElement.classList) | ||
.filter(token => token.startsWith('cdk')) | ||
.join(' '); | ||
|
||
containerElement.classList.add('ngx-overlay-container'); | ||
if (this.overlayContainerClass) { | ||
this.overlayContainerClass.split(' ').forEach(className => { | ||
containerElement.classList.add(className); | ||
}); | ||
} | ||
|
||
const info$ = this.ownerElement$.pipe( | ||
combineLatestWith(isMobile$), | ||
map(([ownerElement, isMobile]) => ({ | ||
offsetX: showParams.offsetX && +showParams.offsetX || 0, | ||
offsetY: showParams.offsetY && +showParams.offsetY || 0, | ||
origin: new CdkOverlayOrigin(new ElementRef((isMobile && document.body) ?? showParams.event?.target ?? ownerElement ?? this.elementRef.nativeElement)), | ||
width: isMobile ? this.widthForMobile : this.width | ||
} as OverlayInfos)) | ||
); | ||
|
||
const updatePosition$ = info$.pipe( | ||
delay(1), | ||
switchMap(() => { | ||
this.overlay?.overlayRef?.updatePosition(); | ||
return EMPTY; | ||
}) | ||
); | ||
|
||
return info$.pipe( | ||
mergeWith(updatePosition$) | ||
); | ||
}), | ||
shareReplay({ bufferSize: 1, refCount: false }) | ||
); | ||
|
||
|
||
this.isVisible$ = this.overlayInfos$.pipe( | ||
map(Boolean), | ||
startWith(false), | ||
distinctUntilChanged() | ||
); | ||
} | ||
|
||
public ngOnChanges(changes: SimpleChanges): void { | ||
if (changes['isMobile']) { | ||
this.isMobileExt$.next(this.isMobile !== undefined ? coerceBooleanProperty(this.isMobile) : undefined); | ||
} | ||
|
||
if (changes['ownerElement']) { | ||
this.ownerElement$.next(this.ownerElement); | ||
} | ||
} | ||
|
||
public get positionPairs(): OverlayConnectionPositionPair[] { | ||
return this.positions; | ||
} | ||
|
||
public get positions(): OverlayConnectionPositionPair[] { | ||
if (!this.isMobile) { | ||
return this._positions; | ||
} else if (this._positionsForMobile) { | ||
return this._positionsForMobile; | ||
} else { | ||
return OverlayConnectionPositionPair.parse('start top start top'); | ||
} | ||
} | ||
|
||
@Input() | ||
public set positions(value: OverlayConnectionPositionPair[] | string) { | ||
this._positions = typeof value === 'string' ? OverlayConnectionPositionPair.parse(value) : value; | ||
} | ||
|
||
/** Si pas null, sera utilisé quand isMobile est vrai. Si null et si isMobile est vrai, | ||
* alors c'est la valeur 'start top start top' qui est utilisée. | ||
* */ | ||
@Input() | ||
public set positionsForMobile(value: OverlayConnectionPositionPair[] | string) { | ||
this._positionsForMobile = typeof value === 'string' ? OverlayConnectionPositionPair.parse(value) : value; | ||
} | ||
|
||
/** Affiche le dialog. */ | ||
public show(eventOrOffsetX?: MouseEvent | number, offsetY?: number): void { | ||
if (typeof eventOrOffsetX === 'number') { | ||
this.show$.next({ offsetX: eventOrOffsetX, offsetY }); | ||
} else { | ||
this.show$.next({ event: eventOrOffsetX, offsetY }); | ||
} | ||
} | ||
|
||
/** Ferme le dialog. */ | ||
public close(): void { | ||
this.hide$.next(); | ||
} | ||
} |
This file contains 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