Skip to content

Commit

Permalink
feat(datepicker): add animation (#5173)
Browse files Browse the repository at this point in the history
  • Loading branch information
Domainv authored Jun 7, 2019
1 parent 8ce5e86 commit d5bc6f8
Show file tree
Hide file tree
Showing 14 changed files with 164 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
DemoDatePickerSelectDatesFromOtherMonthsComponent
} from './demos/select-dates-from-other-months/select-dates-from-other-months';
import { DemoDatePickerAdaptivePositionComponent } from './demos/adaptive-position/adaptive-position';
import { DemoDatePickerAnimatedComponent } from './demos/animated/animated';
import { DemoDatepickerCustomTodayClassComponent } from './demos/custom-today-class/custom-today-class.component';
import { DemoDatePickerSelectWeekComponent } from './demos/select-week/select-week';
import { DemoDatepickerTriggersCustomComponent } from './demos/triggers-custom/triggers-custom';
Expand Down Expand Up @@ -82,6 +83,14 @@ export const demoComponentContent: ContentSection[] = [
description: `<p>with initial state set by <code>bsInlineValue</code> property</p>`,
outlet: DemoDatepickerInlineComponent
},
{
title: 'With animation',
anchor: 'animated',
component: require('!!raw-loader!./demos/animated/animated'),
html: require('!!raw-loader!./demos/animated/animated.html'),
description: `You can enable animation via <code>isAnimated</code> config option`,
outlet: DemoDatePickerAnimatedComponent
},
{
title: 'Adaptive position',
anchor: 'adaptive-position',
Expand Down
16 changes: 16 additions & 0 deletions demo/src/app/components/+datepicker/demos/animated/animated.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<div class="row">
<div class="col-xs-12 col-12 col-md-4 form-group">
<input type="text"
placeholder="Datepicker"
class="form-control"
bsDatepicker
[bsConfig]="{ isAnimated: true }">
</div>
<div class="col-xs-12 col-12 col-md-4 form-group">
<input type="text"
placeholder="Daterangepicker"
class="form-control"
bsDaterangepicker
[bsConfig]="{ isAnimated: true }">
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Component } from '@angular/core';

@Component({
selector: 'demo-datepicker-animated',
templateUrl: './animated.html'
})
export class DemoDatePickerAnimatedComponent {}
10 changes: 6 additions & 4 deletions demo/src/app/components/+datepicker/demos/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,20 @@ import {
DemoDatePickerSelectDatesFromOtherMonthsComponent
} from './select-dates-from-other-months/select-dates-from-other-months';

import { DemoDatePickerAdaptivePositionComponent } from './adaptive-position/adaptive-position';
import { DemoDatePickerAnimatedComponent } from './animated/animated';
import { DemoDatepickerDateCustomClassesComponent } from './date-custom-classes/date-custom-classes'
import { DemoDatePickerSelectWeekComponent } from './select-week/select-week';
import { DemoDatepickerTriggersCustomComponent } from './triggers-custom/triggers-custom';
import { DemoDatepickerTriggersManualComponent } from './triggers-manual/triggers-manual';
import { DemoDatepickerValueChangeEventComponent } from './value-change-event/value-change-event';
import { DemoDatePickerVisibilityEventsComponent } from './visibility-events/visibility-events';
import { DemoDatepickerDateCustomClassesComponent } from './date-custom-classes/date-custom-classes'
import { DemoDatePickerAdaptivePositionComponent } from './adaptive-position/adaptive-position';


export const DEMO_COMPONENTS = [
DatepickerDemoComponent,
DemoDatePickerAdaptivePositionComponent,
DemoDatePickerAnimatedComponent,
DemoDatepickerBasicComponent,
DemoDatepickerByIsOpenPropComponent,
DemoDatepickerChangeLocaleComponent,
Expand All @@ -44,6 +46,7 @@ export const DEMO_COMPONENTS = [
DemoDatePickerConfigObjectComponent,
DemoDatePickerCustomFormatComponent,
DemoDatepickerCustomTodayClassComponent,
DemoDatepickerDateCustomClassesComponent,
DemoDatepickerDateInitialStateComponent,
DemoDatepickerDatesDisabledComponent,
DemoDatepickerDaysDisabledComponent,
Expand All @@ -63,6 +66,5 @@ export const DEMO_COMPONENTS = [
DemoDatepickerTriggersCustomComponent,
DemoDatepickerTriggersManualComponent,
DemoDatepickerValueChangeEventComponent,
DemoDatePickerVisibilityEventsComponent,
DemoDatepickerDateCustomClassesComponent
DemoDatePickerVisibilityEventsComponent
];
8 changes: 7 additions & 1 deletion demo/src/app/components/+datepicker/docs/usage.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

// RECOMMENDED
import { BsDatepickerModule } from 'ngx-bootstrap/datepicker';
// or
import { BsDatepickerModule } from 'ngx-bootstrap';

@NgModule({
imports: [BsDatepickerModule.forRoot(),...]
imports: [
BrowserAnimationsModule,
BsDatepickerModule.forRoot(),
...
]
})
export class AppModule(){}
2 changes: 2 additions & 0 deletions src/datepicker/bs-datepicker.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import {
export class BsDatepickerConfig implements DatepickerRenderOptions {
/** sets use adaptive position */
adaptivePosition = false;
/** turn on/off animation */
isAnimated = false;
value?: Date | Date[];
isDisabled?: boolean;
/**
Expand Down
8 changes: 6 additions & 2 deletions src/datepicker/bs-datepicker.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Component, ViewChild, Renderer2 } from '@angular/core';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { Component, ViewChild, Renderer2 } from '@angular/core';

import { BsDatepickerConfig, BsDatepickerDirective, BsDatepickerModule } from '.';
import { BsDatepickerContainerComponent } from './themes/bs/bs-datepicker-container.component';
Expand Down Expand Up @@ -52,7 +53,10 @@ describe('datepicker:', () => {
beforeEach(
async(() => TestBed.configureTestingModule({
declarations: [TestComponent],
imports: [BsDatepickerModule.forRoot()]
imports: [
BsDatepickerModule.forRoot(),
BrowserAnimationsModule
]
}).compileComponents()
));
beforeEach(() => {
Expand Down
2 changes: 2 additions & 0 deletions src/datepicker/bs-daterangepicker.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ import { BsDatepickerConfig } from './bs-datepicker.config';
export class BsDaterangepickerConfig extends BsDatepickerConfig {
// DatepickerRenderOptions
displayMonths = 2;
/** turn on/off animation */
isAnimated = false;
}
8 changes: 6 additions & 2 deletions src/datepicker/bs-inline-datepicker.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Component, ViewChild } from '@angular/core';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { Component, ViewChild } from '@angular/core';

import { BsDatepickerInlineConfig, BsDatepickerInlineDirective, BsDatepickerModule } from '.';
import { CalendarCellViewModel } from './models';
Expand Down Expand Up @@ -34,7 +35,10 @@ describe('datepicker inline:', () => {
beforeEach(
async(() => TestBed.configureTestingModule({
declarations: [TestComponent],
imports: [BsDatepickerModule.forRoot()]
imports: [
BsDatepickerModule.forRoot(),
BrowserAnimationsModule
]
}).compileComponents()
));
beforeEach(() => {
Expand Down
25 changes: 25 additions & 0 deletions src/datepicker/datepicker-animations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import {
animate,
style,
AnimationTriggerMetadata,
state,
transition,
trigger
} from '@angular/animations';

export const DATEPICKER_ANIMATION_TIMING = '220ms cubic-bezier(0, 0, 0.2, 1)';

export const datepickerAnimation: AnimationTriggerMetadata =
trigger('datepickerAnimation', [
state('animated-down', style({ height: '*', overflow: 'hidden'})),
transition('* => animated-down', [
style({ height: 0, overflow: 'hidden' }),
animate(DATEPICKER_ANIMATION_TIMING)
]),
state('animated-up', style({ height: '*', overflow: 'hidden'})),
transition('* => animated-up', [
style({ height: '*', overflow: 'hidden' }),
animate(DATEPICKER_ANIMATION_TIMING)
]),
transition('* => unanimated', animate('0s'))
]);
42 changes: 35 additions & 7 deletions src/datepicker/themes/bs/bs-datepicker-container.component.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, EventEmitter, OnDestroy, OnInit } from '@angular/core';
import { Component, ElementRef, EventEmitter, OnDestroy, OnInit } from '@angular/core';

import { BsDatepickerAbstractComponent } from '../../base/bs-datepicker-container';
import { BsDatepickerConfig } from '../../bs-datepicker.config';
Expand All @@ -9,29 +9,37 @@ import { BsDatepickerStore } from '../../reducer/bs-datepicker.store';
import { PositioningService } from 'ngx-bootstrap/positioning';

import { Subscription } from 'rxjs';
import { datepickerAnimation } from '../../datepicker-animations';
import { take } from 'rxjs/operators';

@Component({
selector: 'bs-datepicker-container',
providers: [BsDatepickerStore, BsDatepickerEffects],
templateUrl: './bs-datepicker-view.html',
host: {
class: 'bottom',
'(click)': '_stopPropagation($event)',
style: 'position: absolute; display: block;',
role: 'dialog',
'aria-label': 'calendar'
}
},
animations: [datepickerAnimation]
})
export class BsDatepickerContainerComponent extends BsDatepickerAbstractComponent
implements OnInit, OnDestroy {

set value(value: Date) {
this._effects.setValue(value);
}

valueChange: EventEmitter<Date> = new EventEmitter<Date>();
animationState = 'void';

_subs: Subscription[] = [];
constructor(
private _config: BsDatepickerConfig,
private _store: BsDatepickerStore,
private _element: ElementRef,
private _actions: BsDatepickerActions,
_effects: BsDatepickerEffects,
private _positionService: PositioningService
Expand All @@ -42,14 +50,26 @@ export class BsDatepickerContainerComponent extends BsDatepickerAbstractComponen

ngOnInit(): void {
this._positionService.setOptions({
modifiers: {
flip: {
enabled: this._config.adaptivePosition
}
},
modifiers: { flip: { enabled: this._config.adaptivePosition } },
allowedPositions: ['top', 'bottom']
});

this._positionService.event$
.pipe(
take(1)
)
.subscribe(() => {
this._positionService.disable();

if (this._config.isAnimated) {
this.animationState = this.isTopPosition ? 'animated-up' : 'animated-down';

return;
}

this.animationState = 'unanimated';
});

this.isOtherMonthsActive = this._config.selectFromOtherMonth;
this.containerClass = this._config.containerClass;
this._effects
Expand All @@ -73,6 +93,14 @@ export class BsDatepickerContainerComponent extends BsDatepickerAbstractComponen
);
}

get isTopPosition(): boolean {
return this._element.nativeElement.classList.contains('top');
}

positionServiceEnable(): void {
this._positionService.enable();
}

daySelectHandler(day: DayViewModel): void {
const isDisabled = this.isOtherMonthsActive ? day.isDisabled : (day.isOtherMonth || day.isDisabled);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Component, ElementRef, OnDestroy, OnInit } from '@angular/core';
import { BsDatepickerContainerComponent } from './bs-datepicker-container.component';

import { BsDatepickerConfig } from '../../bs-datepicker.config';
Expand All @@ -7,6 +7,7 @@ import { BsDatepickerEffects } from '../../reducer/bs-datepicker.effects';
import { BsDatepickerStore } from '../../reducer/bs-datepicker.store';

import { PositioningService } from 'ngx-bootstrap/positioning';
import { datepickerAnimation } from '../../datepicker-animations';

@Component({
selector: 'bs-datepicker-inline-container',
Expand All @@ -15,17 +16,19 @@ import { PositioningService } from 'ngx-bootstrap/positioning';
host: {
'(click)': '_stopPropagation($event)',
style: 'display: inline-block;'
}
},
animations: [datepickerAnimation]
})
export class BsDatepickerInlineContainerComponent extends BsDatepickerContainerComponent
implements OnInit, OnDestroy {
constructor(
_config: BsDatepickerConfig,
_store: BsDatepickerStore,
_element: ElementRef,
_actions: BsDatepickerActions,
_effects: BsDatepickerEffects,
_positioningService: PositioningService
) {
super(_config, _store, _actions, _effects, _positioningService);
super(_config, _store, _element, _actions, _effects, _positioningService);
}
}
6 changes: 4 additions & 2 deletions src/datepicker/themes/bs/bs-datepicker-view.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
<!-- days calendar view mode -->
<div class="bs-datepicker" [ngClass]="containerClass" *ngIf="viewMode | async">
<div class="bs-datepicker-container">

<div
class="bs-datepicker-container"
[@datepickerAnimation]="animationState"
(@datepickerAnimation.done)="positionServiceEnable()">
<!--calendars-->
<div class="bs-calendar-container" [ngSwitch]="viewMode | async" role="application">
<!--days calendar-->
Expand Down
Loading

0 comments on commit d5bc6f8

Please sign in to comment.