@nebular/theme
Version:
@nebular/theme
414 lines • 13.8 kB
JavaScript
/*
* @license
* Copyright Akveo. All Rights Reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/
import { Component, ComponentFactoryResolver, EventEmitter, Inject, Input, Output, Type, Optional, } from '@angular/core';
import { takeUntil } from 'rxjs/operators';
import { ReplaySubject, Subject } from 'rxjs';
import { NbComponentPortal } from '../cdk/overlay/mapping';
import { NbAdjustment, NbPosition, NbPositionBuilderService, } from '../cdk/overlay/overlay-position';
import { NbOverlayService, patch } from '../cdk/overlay/overlay-service';
import { NbTrigger, NbTriggerStrategyBuilderService } from '../cdk/overlay/overlay-trigger';
import { NbDatepickerContainerComponent } from './datepicker-container.component';
import { NB_DOCUMENT } from '../../theme.options';
import { NbCalendarRangeComponent } from '../calendar/calendar-range.component';
import { NbCalendarComponent } from '../calendar/calendar.component';
import { NbCalendarSize, NbCalendarViewMode, } from '../calendar-kit/model';
import { NbDateService } from '../calendar-kit/services/date.service';
import { NB_DATE_SERVICE_OPTIONS, NbDatepicker } from './datepicker.directive';
import { convertToBoolProperty } from '../helpers';
/**
* The `NbBasePicker` component concentrates overlay manipulation logic.
* */
export class NbBasePicker extends NbDatepicker {
constructor(overlay, positionBuilder, triggerStrategyBuilder, cfr, dateService, dateServiceOptions) {
super();
this.overlay = overlay;
this.positionBuilder = positionBuilder;
this.triggerStrategyBuilder = triggerStrategyBuilder;
this.cfr = cfr;
this.dateService = dateService;
this.dateServiceOptions = dateServiceOptions;
/**
* Size of the calendar and entire components.
* Can be 'medium' which is default or 'large'.
* */
this.size = NbCalendarSize.MEDIUM;
this.init$ = new ReplaySubject();
/**
* Stream of picker changes. Required to be the subject because picker hides and shows and picker
* change stream becomes recreated.
* */
this.onChange$ = new Subject();
this.overlayOffset = 8;
this.destroy$ = new Subject();
this.blur$ = new Subject();
}
/**
* Returns picker instance.
* */
get picker() {
return this.pickerRef && this.pickerRef.instance;
}
/**
* Stream of picker value changes.
* */
get valueChange() {
return this.onChange$.asObservable();
}
get isShown() {
return this.ref && this.ref.hasAttached();
}
get init() {
return this.init$.asObservable();
}
/**
* Emits when datepicker looses focus.
*/
get blur() {
return this.blur$.asObservable();
}
/**
* Datepicker knows nothing about host html input element.
* So, attach method attaches datepicker to the host input element.
* */
attach(hostRef) {
this.hostRef = hostRef;
this.subscribeOnTriggers();
}
getValidatorConfig() {
return { min: this.min, max: this.max, filter: this.filter };
}
show() {
if (!this.ref) {
this.createOverlay();
}
this.openDatepicker();
}
shouldHide() {
return this.hideOnSelect && !!this.value;
}
hide() {
if (this.ref) {
this.ref.detach();
}
// save current value if picker was rendered
if (this.picker) {
this.queue = this.value;
this.pickerRef.destroy();
this.pickerRef = null;
this.container = null;
}
}
createOverlay() {
this.positionStrategy = this.createPositionStrategy();
this.ref = this.overlay.create({
positionStrategy: this.positionStrategy,
scrollStrategy: this.overlay.scrollStrategies.reposition(),
});
this.subscribeOnPositionChange();
}
openDatepicker() {
this.container = this.ref.attach(new NbComponentPortal(NbDatepickerContainerComponent, null, null, this.cfr));
this.instantiatePicker();
this.subscribeOnValueChange();
this.writeQueue();
this.patchWithInputs();
this.pickerRef.changeDetectorRef.markForCheck();
}
createPositionStrategy() {
return this.positionBuilder
.connectedTo(this.hostRef)
.position(NbPosition.BOTTOM)
.offset(this.overlayOffset)
.adjustment(NbAdjustment.COUNTERCLOCKWISE);
}
subscribeOnPositionChange() {
this.positionStrategy.positionChange
.pipe(takeUntil(this.destroy$))
.subscribe((position) => patch(this.container, { position }));
}
createTriggerStrategy() {
return this.triggerStrategyBuilder
.trigger(NbTrigger.FOCUS)
.host(this.hostRef.nativeElement)
.container(() => this.container)
.build();
}
subscribeOnTriggers() {
this.triggerStrategy = this.createTriggerStrategy();
this.triggerStrategy.show$.subscribe(() => this.show());
this.triggerStrategy.hide$.subscribe(() => {
this.blur$.next();
this.hide();
});
}
instantiatePicker() {
this.pickerRef = this.container.instance.attach(new NbComponentPortal(this.pickerClass, null, null, this.cfr));
}
/**
* Subscribes on picker value changes and emit data through this.onChange$ subject.
* */
subscribeOnValueChange() {
this.pickerValueChange.subscribe(date => {
this.onChange$.next(date);
});
}
patchWithInputs() {
this.picker.boundingMonth = this.boundingMonth;
this.picker.startView = this.startView;
this.picker.min = this.min;
this.picker.max = this.max;
this.picker.filter = this.filter;
this.picker._cellComponent = this.dayCellComponent;
this.picker._monthCellComponent = this.monthCellComponent;
this.picker._yearCellComponent = this.yearCellComponent;
this.picker.size = this.size;
this.picker.showNavigation = this.showNavigation;
this.picker.visibleDate = this.visibleDate;
this.picker.showWeekNumber = this.showWeekNumber;
this.picker.weekNumberSymbol = this.weekNumberSymbol;
}
checkFormat() {
if (this.dateService.getId() === 'native' && this.format) {
throw new Error('Can\'t format native date. To use custom formatting you have to install @nebular/moment or ' +
'@nebular/date-fns package and import NbMomentDateModule or NbDateFnsDateModule accordingly.' +
'More information at "Formatting issue" ' +
'https://akveo.github.io/nebular/docs/components/datepicker/overview#nbdatepickercomponent');
}
const isFormatSet = this.format || (this.dateServiceOptions && this.dateServiceOptions.format);
if (this.dateService.getId() === 'date-fns' && !isFormatSet) {
throw new Error('format is required when using NbDateFnsDateModule');
}
}
}
export class NbBasePickerComponent extends NbBasePicker {
constructor(document, positionBuilder, triggerStrategyBuilder, overlay, cfr, dateService, dateServiceOptions) {
super(overlay, positionBuilder, triggerStrategyBuilder, cfr, dateService, dateServiceOptions);
/**
* Defines if we should render previous and next months
* in the current month view.
* */
this.boundingMonth = true;
/**
* Defines starting view for calendar.
* */
this.startView = NbCalendarViewMode.DATE;
/**
* Size of the calendar and entire components.
* Can be 'medium' which is default or 'large'.
* */
this.size = NbCalendarSize.MEDIUM;
/**
* Hide picker when a date or a range is selected, `true` by default
* @type {boolean}
*/
this.hideOnSelect = true;
/**
* Determines should we show calendars navigation or not.
* @type {boolean}
*/
this.showNavigation = true;
/**
* Sets symbol used as a header for week numbers column
* */
this.weekNumberSymbol = '#';
this._showWeekNumber = false;
/**
* Determines picker overlay offset (in pixels).
* */
this.overlayOffset = 8;
}
/**
* Determines should we show week numbers column.
* False by default.
* */
get showWeekNumber() {
return this._showWeekNumber;
}
set showWeekNumber(value) {
this._showWeekNumber = convertToBoolProperty(value);
}
ngOnInit() {
this.checkFormat();
}
ngOnChanges(changes) {
if (changes.format && !changes.format.isFirstChange()) {
this.checkFormat();
}
}
ngAfterViewInit() {
this.init$.next();
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
this.hide();
this.init$.complete();
if (this.ref) {
this.ref.dispose();
}
if (this.triggerStrategy) {
this.triggerStrategy.destroy();
}
}
get pickerValueChange() {
return;
}
get value() {
return undefined;
}
set value(value) { }
writeQueue() {
}
}
NbBasePickerComponent.decorators = [
{ type: Component, args: [{
template: ''
},] }
];
NbBasePickerComponent.ctorParameters = () => [
{ type: undefined, decorators: [{ type: Inject, args: [NB_DOCUMENT,] }] },
{ type: NbPositionBuilderService },
{ type: NbTriggerStrategyBuilderService },
{ type: NbOverlayService },
{ type: ComponentFactoryResolver },
{ type: NbDateService },
{ type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [NB_DATE_SERVICE_OPTIONS,] }] }
];
NbBasePickerComponent.propDecorators = {
format: [{ type: Input }],
boundingMonth: [{ type: Input }],
startView: [{ type: Input }],
min: [{ type: Input }],
max: [{ type: Input }],
filter: [{ type: Input }],
dayCellComponent: [{ type: Input }],
monthCellComponent: [{ type: Input }],
yearCellComponent: [{ type: Input }],
size: [{ type: Input }],
visibleDate: [{ type: Input }],
hideOnSelect: [{ type: Input }],
showNavigation: [{ type: Input }],
weekNumberSymbol: [{ type: Input }],
showWeekNumber: [{ type: Input }],
overlayOffset: [{ type: Input }]
};
/**
* The DatePicker components itself.
* Provides a proxy to `NbCalendar` options as well as custom picker options.
*/
export class NbDatepickerComponent extends NbBasePickerComponent {
constructor() {
super(...arguments);
this.pickerClass = NbCalendarComponent;
}
/**
* Date which will be rendered as selected.
* */
set date(date) {
this.value = date;
}
/**
* Emits date when selected.
* */
get dateChange() {
return this.valueChange;
}
get value() {
return this.picker ? this.picker.date : undefined;
}
set value(date) {
if (!this.picker) {
this.queue = date;
return;
}
if (date) {
this.visibleDate = date;
this.picker.visibleDate = date;
this.picker.date = date;
}
}
get pickerValueChange() {
return this.picker.dateChange;
}
writeQueue() {
if (this.queue) {
const date = this.queue;
this.queue = null;
this.value = date;
}
}
}
NbDatepickerComponent.decorators = [
{ type: Component, args: [{
selector: 'nb-datepicker',
template: ''
},] }
];
NbDatepickerComponent.propDecorators = {
date: [{ type: Input }],
dateChange: [{ type: Output }]
};
/**
* The RangeDatePicker components itself.
* Provides a proxy to `NbCalendarRange` options as well as custom picker options.
*/
export class NbRangepickerComponent extends NbBasePickerComponent {
constructor() {
super(...arguments);
this.pickerClass = NbCalendarRangeComponent;
}
/**
* Range which will be rendered as selected.
* */
set range(range) {
this.value = range;
}
/**
* Emits range when start selected and emits again when end selected.
* */
get rangeChange() {
return this.valueChange;
}
get value() {
return this.picker ? this.picker.range : undefined;
}
set value(range) {
if (!this.picker) {
this.queue = range;
return;
}
if (range) {
const visibleDate = range && range.start;
this.visibleDate = visibleDate;
this.picker.visibleDate = visibleDate;
this.picker.range = range;
}
}
get pickerValueChange() {
return this.picker.rangeChange;
}
shouldHide() {
return super.shouldHide() && !!(this.value && this.value.start && this.value.end);
}
writeQueue() {
if (this.queue) {
const range = this.queue;
this.queue = null;
this.value = range;
}
}
}
NbRangepickerComponent.decorators = [
{ type: Component, args: [{
selector: 'nb-rangepicker',
template: ''
},] }
];
NbRangepickerComponent.propDecorators = {
range: [{ type: Input }],
rangeChange: [{ type: Output }]
};
//# sourceMappingURL=datepicker.component.js.map