Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
3 changes: 2 additions & 1 deletion angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,8 @@
"options": {
"main": "projects/toppy/src/test.ts",
"tsConfig": "projects/toppy/tsconfig.spec.json",
"karmaConfig": "projects/toppy/karma.conf.js"
"karmaConfig": "projects/toppy/karma.conf.js",
"codeCoverage": true
}
},
"lint": {
Expand Down
41 changes: 13 additions & 28 deletions projects/toppy/src/lib/config.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,14 @@
import { Injectable } from '@angular/core';
import { BaseConfig } from './models';
import { ToppyConfig } from './models';

export function ConfigFactory() {
return new Config();
}

@Injectable({
providedIn: 'root',
useFactory: ConfigFactory
})
export class Config implements BaseConfig {
backdrop = false;
containerClass = 'toppy-container';
wrapperClass = 'toppy-wrapper';
backdropClass = 'toppy-backdrop';
dismissOnDocumentClick = true;
parentElement = null;
watchDocClick = true;
watchWindowResize = true;
windowResizeCallback() {}
docClickCallback() {}
set(config: Partial<BaseConfig>) {
// tslint:disable-next-line:forin
for (const configName in config) {
this[configName] = config[configName];
}
}
}
export const DefaultConfig: ToppyConfig = {
backdrop: false,
containerClass: 'toppy-container',
wrapperClass: 'toppy-wrapper',
backdropClass: 'toppy-backdrop',
dismissOnDocumentClick: true,
parentElement: null,
watchDocClick: true,
watchWindowResize: true,
windowResizeCallback: () => {},
docClickCallback: () => {}
};
32 changes: 22 additions & 10 deletions projects/toppy/src/lib/host-container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ import { CurrentOverlay } from './current-overlay';
import { HostArgs, HostContentType } from './models';
import { ToppyRef } from './toppy-ref';

@Injectable()
@Injectable({
providedIn: 'root'
})
export class HostContainer {
private _compFac: ComponentFactory<any>;
private _compRef: ComponentRef<any>;
Expand All @@ -24,9 +26,9 @@ export class HostContainer {
private _content: any;
toppyRef: (id: string) => ToppyRef;
constructor(
private appRef: ApplicationRef,
private compFacResolver: ComponentFactoryResolver,
private injector: Injector
private _appRef: ApplicationRef,
private _compFacResolver: ComponentFactoryResolver,
private _injector: Injector
) {}

configure(
Expand All @@ -47,7 +49,7 @@ export class HostContainer {
return template.createEmbeddedView(ctx);
}
createViewFromComponent(component, props: any = {}): ViewRef {
this._compFac = this.compFacResolver.resolveComponentFactory(component);
this._compFac = this._compFacResolver.resolveComponentFactory(component);
const dataInjector = Injector.create({
providers: [
{
Expand All @@ -56,7 +58,7 @@ export class HostContainer {
deps: []
}
],
parent: this.injector
parent: this._injector
});
this._compRef = this._compFac.create(dataInjector);
this._compIns = <ComponentInstance>new ComponentInstance(this._compRef.instance, props).getInstance();
Expand All @@ -69,12 +71,12 @@ export class HostContainer {
switch (this._contentType) {
case 'COMPONENT':
view = this.createViewFromComponent(this._content, this._contentProps);
this.appRef.attachView(view);
this._appRef.attachView(view);
viewEl = this.getComponentViewEl();
break;
case 'TEMPLATEREF':
view = this.createViewFromTemplate(this._content);
this.appRef.attachView(view);
this._appRef.attachView(view);
viewEl = view.rootNodes[0];
break;
case 'STRING':
Expand All @@ -91,12 +93,12 @@ export class HostContainer {
if (!this._compRef) {
return;
}
this.appRef.detachView(this._compRef.hostView);
this._appRef.detachView(this._compRef.hostView);
this._compRef.destroy();
}

getComponentViewEl(): null | HTMLElement {
if (this.appRef.viewCount === 0) {
if (this._appRef.viewCount === 0) {
return null;
}
return (this._compRef.hostView as EmbeddedViewRef<any>).rootNodes[0] as HTMLElement;
Expand All @@ -105,4 +107,14 @@ export class HostContainer {
getCompIns() {
return this._compIns;
}

reset() {
this._contentType = null;
this._contentProps = null;
this._content = null;
}

getNewInstance() {
return new HostContainer(this._appRef, this._compFacResolver, this._injector);
}
}
2 changes: 1 addition & 1 deletion projects/toppy/src/lib/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export interface ContainerSize {
height: string | number;
}

export interface BaseConfig {
export interface ToppyConfig {
backdrop: boolean;
containerClass: string;
wrapperClass: string;
Expand Down
32 changes: 26 additions & 6 deletions projects/toppy/src/lib/overlay-instance.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import { Injectable, OnDestroy } from '@angular/core';
import { Subject, Subscription } from 'rxjs';
import { Config } from './config';
import { DomHelper } from './helper/dom';
import { EventBus } from './helper/event-bus';
import { ToppyConfig } from './models';
import { DefaultPosition } from './position';
import { Position } from './position/position';
import { filter, map } from 'rxjs/operators';

@Injectable()
@Injectable({
providedIn: 'root'
})
export class OverlayInstance implements OnDestroy {
computePosition: Subject<boolean> = new Subject();

config: ToppyConfig;
private _overlayID: string;
private _position: Position;
private _viewEl: HTMLElement;
Expand All @@ -18,7 +21,12 @@ export class OverlayInstance implements OnDestroy {
private _backdropEl: HTMLElement;
private _positionSubscription: Subscription;

constructor(public config: Config, private _eventBus: EventBus, private _dom: DomHelper) {}
constructor(private _eventBus: EventBus, private _dom: DomHelper) {}

setConfig(config: ToppyConfig) {
this.config = config;
return this;
}

configure(position: Position = new DefaultPosition(), overlayID?: string) {
this._position = position;
Expand All @@ -44,7 +52,7 @@ export class OverlayInstance implements OnDestroy {

this._wrapperEl = this._dom.createElement('div', {
class: this.config.wrapperClass,
style: 'position: absolute;visibility:hidden;opacity:0;transition:opacity 0.5s ease;'
style: 'position: absolute;visibility:hidden;opacity:0;transition:opacity 0.2s ease;'
});

if (this.config.backdrop) {
Expand All @@ -56,8 +64,10 @@ export class OverlayInstance implements OnDestroy {
}

this._setPosition();
this._position.setEventBus(this._eventBus);
this._dom.insertChildren(this.config.parentElement || this._dom.html.BODY, this._containerEl, this._wrapperEl);
this._eventBus.post({ name: 'ATTACHED', data: null });
this._onNewComputedPosition();
this._watchPositionChange();
return this;
}
Expand All @@ -75,6 +85,10 @@ export class OverlayInstance implements OnDestroy {
return this._containerEl;
}

getNewInstance() {
return new OverlayInstance(this._eventBus, this._dom);
}

destroy(): void {
this._dom.removeElement(this._containerEl);
this._eventBus.post({ name: 'DETACHED', data: null });
Expand Down Expand Up @@ -105,7 +119,13 @@ export class OverlayInstance implements OnDestroy {
this._eventBus.post({ name: 'POSITION_UPDATED', data: null });
}

private _watchPositionChange(): void {
private _watchPositionChange() {
this._eventBus.watch().pipe(filter(data => data.name === 'NEW_DYN_POS'), map(d => d.data)).subscribe(e => {
this._dom.setPositions(this._wrapperEl, {left: e.x, top: e.y});
});
}

private _onNewComputedPosition(): void {
this._positionSubscription = this.computePosition.subscribe(_ => {
this._setPosition(true);
});
Expand Down
29 changes: 29 additions & 0 deletions projects/toppy/src/lib/position/cursor-position.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { PositionCoOrds } from '../models';
import { Position } from './position';
import { EventBus } from '../helper/event-bus';
import { animationFrameScheduler, fromEvent } from 'rxjs';
import { map, tap, debounceTime, observeOn, distinctUntilChanged } from 'rxjs/operators';

export class CursorPosition extends Position {
private _config: { src: HTMLElement};
constructor(config) {
super();
this._config = { ...this._config, ...config };
this.attachEvent().subscribe(); // TODO: flush on destroy
}
updateConfig(newConfig) {
this._config = { ...this._config, ...newConfig };
}
getPositions(): PositionCoOrds {
return { };
}
attachEvent() {
return fromEvent(this._config.src, 'mousemove').pipe(
map((e: any) => ({x: e.clientX, y: e.clientY})),
debounceTime(1),
observeOn(animationFrameScheduler),
distinctUntilChanged(),
tap(data => this.eventBus.post({name: 'NEW_DYN_POS', data})),
);
}
}
1 change: 1 addition & 0 deletions projects/toppy/src/lib/position/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export { GlobalPosition } from './global-position';
// export { Position } from './position';
export { RelativePosition } from './relative-position';
export { SlidePosition } from './slide-position';
export { CursorPosition } from './cursor-position';
6 changes: 6 additions & 0 deletions projects/toppy/src/lib/position/position.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import { EventBus } from '../helper/event-bus';

// import { PositionCoOrds } from '../models';

export abstract class Position {
eventBus: EventBus;
abstract getPositions(host: HTMLElement): any;
abstract updateConfig(config: object): any;
setEventBus(eventBus) {
this.eventBus = eventBus;
}
getClassName(): string {
return this.constructor.name.replace('Position', '-position').toLocaleLowerCase();
}
Expand Down
8 changes: 6 additions & 2 deletions projects/toppy/src/lib/toppy-ref.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { animationFrameScheduler, fromEvent, merge, Observable, Subject } from 'rxjs';
import { debounceTime, distinctUntilChanged, filter, map, observeOn, skipWhile, takeUntil, tap } from 'rxjs/operators';
import { Config } from './config';
import { EventBus } from './helper/event-bus';
import { HostContainer } from './host-container';
import { ToppyConfig } from './models';
import { OverlayInstance } from './overlay-instance';

export class ToppyRef {
Expand All @@ -13,7 +13,7 @@ export class ToppyRef {
private _overlay: OverlayInstance,
private _host: HostContainer,
private _eventBus: EventBus,
private _config: Config,
private _config: ToppyConfig,
public overlayID: string
) {}

Expand Down Expand Up @@ -74,6 +74,10 @@ export class ToppyRef {
);
}

getConfig() {
return this._config;
}

updatePosition(positionConfig) {
this._overlay.updatePositionConfig(positionConfig);
}
Expand Down
8 changes: 2 additions & 6 deletions projects/toppy/src/lib/toppy.module.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
import { NgModule } from "@angular/core";
import { HostContainer } from "./host-container";
import { OverlayInstance } from "./overlay-instance";
import { NgModule } from '@angular/core';

@NgModule({
providers: [HostContainer, OverlayInstance]
})
@NgModule()
export class ToppyModule {}
Loading