Skip to content
This repository was archived by the owner on Nov 30, 2022. It is now read-only.

Commit bc0c443

Browse files
committed
feat(dialog): add dialog component
1 parent f484af9 commit bc0c443

14 files changed

+508
-4
lines changed

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"scripts": {
2020
"build": "ng build core && ng build google-maps",
2121
"build:prod": "ng build core --prod && ng build google-maps --prod",
22+
"gh-pages": "ng build --base-href 'https://fivethree-team.github.io/fivethree/' && npx ngh --dir=www",
2223
"changelog": "conventional-changelog -p angular -i ./CHANGELOG.md -s"
2324
},
2425
"private": true,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<div #backdrop class="backdrop" [@backdropAnim] (@backdropAnim.done)="backdropAnimDone($event)" (click)="backdropClose? hideDialog() : false"
2+
*ngIf="animationState !== 'hidden' && backdrop">
3+
</div>
4+
<div #card [@dialogAnim]="animationState" (@dialogAnim.done)="onDialogAnimationDone($event)" mode="md" class="gg-dialog">
5+
<ng-content></ng-content>
6+
</div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
:host{
2+
position: absolute;
3+
z-index: 5002;
4+
margin: 0;
5+
border-radius: 0;
6+
width: 100%;
7+
}
8+
9+
.top{
10+
top:0;
11+
}
12+
13+
.bottom{
14+
bottom: 0;
15+
}
16+
17+
.floating{
18+
margin: 16px 20px;
19+
border-radius: 8px;
20+
width: calc(100% - 40px);
21+
box-shadow: 0 4px 16px rgba(0,0,0,.12);
22+
}
23+
.fullscreen{
24+
margin: 0;
25+
border-radius: 0px;
26+
width: 100%;
27+
height: 100%;
28+
box-shadow: 0 4px 16px rgba(0,0,0,.12);
29+
}
30+
31+
.rounded-top{
32+
border-bottom-left-radius: 12px;
33+
border-bottom-right-radius: 12px;
34+
}
35+
36+
.rounded-bottom{
37+
border-top-left-radius: 12px;
38+
border-top-right-radius: 12px;
39+
}
40+
41+
.backdrop{
42+
background: rgba(0,0,0,.22);
43+
position: absolute;
44+
top: 0;
45+
bottom: 0;
46+
left: 0;
47+
right: 0;
48+
z-index: 5001;
49+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2+
3+
import { DialogComponent } from './dialog.component';
4+
5+
describe('DialogComponent', () => {
6+
let component: DialogComponent;
7+
let fixture: ComponentFixture<DialogComponent>;
8+
9+
beforeEach(async(() => {
10+
TestBed.configureTestingModule({
11+
declarations: [ DialogComponent ]
12+
})
13+
.compileComponents();
14+
}));
15+
16+
beforeEach(() => {
17+
fixture = TestBed.createComponent(DialogComponent);
18+
component = fixture.componentInstance;
19+
fixture.detectChanges();
20+
});
21+
22+
it('should create', () => {
23+
expect(component).toBeTruthy();
24+
});
25+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
import { EventEmitter, Output } from '@angular/core';
2+
import { Component, OnInit, Input, Renderer2, ViewChild, ElementRef, ChangeDetectorRef } from '@angular/core';
3+
import Hammer from 'hammerjs';
4+
import { fromEvent } from 'rxjs';
5+
import { throttleTime, reduce } from 'rxjs/operators';
6+
import { Subscription } from 'rxjs';
7+
import { trigger, transition, style, animate, state } from '@angular/animations';
8+
9+
@Component({
10+
selector: 'fiv-dialog',
11+
templateUrl: './dialog.component.html',
12+
styleUrls: ['./dialog.component.scss'],
13+
animations: [
14+
trigger('dialogAnim', [
15+
transition('hidden => slideIn-top', [
16+
style({
17+
transform: 'translateY(-100%)'
18+
}),
19+
animate('275ms 100ms cubic-bezier(0.32,1,0.23,1)')
20+
]),
21+
transition('hidden => slideIn-bottom', [
22+
style({
23+
transform: 'translateY(100%)'
24+
}),
25+
animate('275ms 100ms cubic-bezier(0.32,1,0.23,1)')
26+
]),
27+
transition('hidden => fadeIn-bottom', [
28+
style({
29+
opacity: 0
30+
}),
31+
animate('360ms ease-out')
32+
]),
33+
transition('hidden => fadeIn-top', [
34+
style({
35+
opacity: 0
36+
}),
37+
animate('360ms ease-out')
38+
]),
39+
transition('hidden => fadeIn-center', [
40+
style({
41+
opacity: 0,
42+
top: '50%',
43+
transform: 'translateY(-50%)',
44+
}),
45+
animate('360ms ease-out')
46+
]),
47+
transition('hidden => slideIn-center', [
48+
style({
49+
top: '50%',
50+
transform: 'translateY(-25%)',
51+
opacity: 0
52+
}),
53+
animate('275ms 100ms cubic-bezier(0.32,1,0.23,1)')
54+
]),
55+
transition('slideIn-center => hidden', [
56+
animate('120ms ease-out', style({
57+
// top: '50%',
58+
// transform: 'translateY(+50%)',
59+
opacity: 0
60+
}))
61+
]),
62+
transition('* => hidden', [
63+
animate('240ms ease-out')
64+
]),
65+
state('hidden', style({
66+
display: 'none',
67+
opacity: '0',
68+
})
69+
),
70+
state('slideIn-top', style({
71+
top: 0,
72+
})
73+
),
74+
state('slideIn-bottom', style({
75+
bottom: 0
76+
})
77+
),
78+
state('fadeIn-top', style({
79+
top: 0
80+
})
81+
),
82+
state('fadeIn-bottom', style({
83+
bottom: 0
84+
})
85+
),
86+
state('fadeIn-center', style({
87+
top: '50%',
88+
transform: 'translateY(-50%)',
89+
'margin-top': 0
90+
})
91+
),
92+
state('slideIn-center', style({
93+
top: '50%',
94+
transform: 'translateY(-50%)',
95+
'margin-top': 0
96+
})
97+
),
98+
]), trigger('backdropAnim', [
99+
transition('void => *', [
100+
style({
101+
opacity: 0
102+
}),
103+
animate('275ms 100ms cubic-bezier(0.32,1,0.23,1)')
104+
]),
105+
transition('* => void', [
106+
animate('120ms 100ms cubic-bezier(0.32,1,0.23,1)'), style({
107+
opacity: 0
108+
}),
109+
])
110+
])]
111+
})
112+
export class DialogComponent implements OnInit {
113+
114+
animationState = 'hidden';
115+
116+
@Input() animation: 'slideIn' | 'fadeIn' = 'slideIn';
117+
@Input() verticalAlign: 'top' | 'bottom' | 'center' = 'bottom';
118+
@Input() backdrop = false;
119+
@Input() backdropClose = true;
120+
@Input() swipeEnabled = true;
121+
122+
@Output() fivClose: EventEmitter<DialogComponent> = new EventEmitter();
123+
@Output() fivOpen: EventEmitter<DialogComponent> = new EventEmitter();
124+
125+
@ViewChild('card') card: ElementRef;
126+
@ViewChild('backdrop') backdropElem: ElementRef;
127+
128+
private panSubs: Subscription[] = [];
129+
130+
constructor(private renderer: Renderer2, public change: ChangeDetectorRef) {
131+
132+
}
133+
134+
setupPan(elem: ElementRef, threshold: number) {
135+
136+
if (!this.swipeEnabled) {
137+
return;
138+
}
139+
140+
const hammer = new Hammer(elem);
141+
hammer.get('pan').set({ direction: Hammer.DIRECTION_ALL });
142+
143+
const panup = fromEvent(hammer, 'panup')
144+
.pipe(
145+
throttleTime(2)
146+
)
147+
.subscribe(res => {
148+
console.log('panup', res);
149+
this.onSwipeUp(res, threshold);
150+
});
151+
152+
const pandown = fromEvent(hammer, 'pandown')
153+
.pipe(
154+
throttleTime(2)
155+
)
156+
.subscribe(res => {
157+
console.log('pandown sub', res);
158+
this.onSwipeDown(res, threshold);
159+
});
160+
161+
const panend = fromEvent(hammer, 'panend pancancel')
162+
.subscribe((res: any) => {
163+
if (res.distance < threshold) {
164+
this.renderer.setStyle(this.card.nativeElement, 'transform', `translateY(0px)`);
165+
}
166+
});
167+
168+
this.panSubs.push(pandown, panup, panend);
169+
170+
171+
}
172+
173+
ngOnInit() {
174+
console.log(this.card);
175+
}
176+
177+
showDialog() {
178+
this.animationState = `${this.animation}-${this.verticalAlign}`;
179+
180+
}
181+
182+
hideDialog() {
183+
this.animationState = 'hidden';
184+
this.fivClose.emit(this);
185+
this.panSubs.forEach(sub => {
186+
sub.unsubscribe();
187+
});
188+
}
189+
190+
onSwipeUp(event, threshold) {
191+
console.log(Math.exp(event.distance / 50));
192+
const velocity = 1 + Math.exp(event.distance / 50) / 50;
193+
194+
if (this.verticalAlign === 'top') {
195+
this.renderer.setStyle(this.card.nativeElement, 'transform', `translateY(-${event.distance * velocity}px)`);
196+
if (event.distance > threshold) {
197+
console.log('swipe down happened');
198+
this.hideDialog();
199+
}
200+
}
201+
}
202+
203+
onSwipeDown(event, threshold) {
204+
const velocity = 1 + Math.exp(event.distance / 50) / 50;
205+
console.log(velocity);
206+
if (this.verticalAlign === 'bottom' || this.verticalAlign === 'center') {
207+
this.renderer.setStyle(this.card.nativeElement, 'transform', `translateY(${event.distance * velocity}px)`);
208+
if (event.distance > threshold) {
209+
console.log('swipe down happened');
210+
this.hideDialog();
211+
}
212+
}
213+
214+
}
215+
216+
onDialogAnimationDone(event) {
217+
if (event.toState === 'hidden') {
218+
this.renderer.setStyle(this.card.nativeElement, 'transform', `translateY(0px)`);
219+
}
220+
if (event.fromState === 'hidden') {
221+
this.setupPan(this.card.nativeElement, 58);
222+
this.fivOpen.emit(this);
223+
}
224+
}
225+
226+
backdropAnimDone(event) {
227+
console.log(this.backdropElem, event);
228+
if (event.fromState === 'void') {
229+
// this.change.detectChanges();
230+
console.log(this.backdropElem.nativeElement);
231+
this.setupPan(this.backdropElem.nativeElement, 112);
232+
}
233+
}
234+
235+
}

projects/core/src/lib/fivethree.core.module.ts

+15-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import { LoadingRefresherContentComponent } from './loading-refresher-content/loading-refresher-content.component';
21
import { FormsModule } from '@angular/forms';
32
import { NgModule } from '@angular/core';
43
import { CommonModule } from '@angular/common';
54
import { IonicModule } from '@ionic/angular';
5+
import { HammerGestureConfig, HAMMER_GESTURE_CONFIG } from '@angular/platform-browser';
6+
import { Hammer } from 'hammerjs';
67
import { StepperComponent } from './stepper/stepper.component';
78
import { StepComponent } from './step/step.component';
89
import { StepHeaderComponent } from './step-header/step-header.component';
@@ -29,6 +30,15 @@ import { PullDirective } from './directives/pull.directive';
2930
import { LoadingSpinnerComponent } from './loading-spinner/loading-spinner.component';
3031
import { StepperHorizontalComponent } from './stepper-horizontal/stepper-horizontal.component';
3132
import { IconComponent } from './icon/icon.component';
33+
import { DialogComponent } from './dialog/dialog.component';
34+
import { LoadingRefresherContentComponent } from './loading-refresher-content/loading-refresher-content.component';
35+
36+
37+
export class MyHammerConfig extends HammerGestureConfig {
38+
overrides = <any>{
39+
pan: { direction: Hammer.DIRECTION_VERTICAL, threshold: 3 },
40+
};
41+
}
3242

3343
@NgModule({
3444
imports: [
@@ -63,7 +73,8 @@ import { IconComponent } from './icon/icon.component';
6373
LoadingRefresherContentComponent,
6474
LoadingSpinnerComponent,
6575
StepperHorizontalComponent,
66-
IconComponent
76+
IconComponent,
77+
DialogComponent
6778
],
6879
exports: [
6980
ExpandableComponent,
@@ -92,7 +103,8 @@ import { IconComponent } from './icon/icon.component';
92103
LoadingRefresherContentComponent,
93104
LoadingSpinnerComponent,
94105
StepperHorizontalComponent,
95-
IconComponent
106+
IconComponent,
107+
DialogComponent
96108
]
97109
})
98110
export class FivethreeCoreModule { }

projects/core/src/public_api.ts

+4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ export * from './lib/bottom-sheet/drawer-state';
1010
export * from './lib/app-bar/app-bar.component';
1111
export * from './lib/bottom-sheet/bottom-sheet.component';
1212
export * from './lib/bottom-sheet/bottom-sheet-content/bottom-sheet-content.component';
13+
export * from './lib/collapsable-menu/collapsable-menu-button/collapsable-menu-button.component';
14+
export * from './lib/dialog/dialog.component';
1315
export * from './lib/expandable/expandable.component';
1416
export * from './lib/loading-button/loading-button.component';
1517
export * from './lib/loading-content/loading-content.component';
@@ -21,6 +23,8 @@ export * from './lib/step/step.component';
2123
export * from './lib/step-content/step-content.component';
2224
export * from './lib/step-header/step-header.component';
2325
export * from './lib/stepper/stepper.component';
26+
export * from './lib/stepper-horizontal/stepper-horizontal.component';
27+
export * from './lib/toolbar-search/toolbar-search.component';
2428

2529
// export services
2630
export * from './lib/loading/loading.service';

0 commit comments

Comments
 (0)