diff --git a/src/demo-app/date-picker/date-picker-demo.html b/src/demo-app/date-picker/date-picker-demo.html new file mode 100644 index 000000000000..b4f52dae3f7d --- /dev/null +++ b/src/demo-app/date-picker/date-picker-demo.html @@ -0,0 +1,33 @@ + + Basic + + + + +

{{ date | date: 'dd-MMMM-y' }}

+
+
+ + + Two selections + + + + + +

{{ date01 | date: 'dd-MMMM-y' }} to {{ date02 | date: 'dd-MMMM-y' }}

+

{{ _date2.Days }} days selected

+
+
+ + + Two date picker + + + + + +

{{ ini | date: 'dd-MMMM-y'}} to {{ end | date: 'dd-MMMM-y'}}

+

{{ _date3.Days }} days selected

+
+
diff --git a/src/demo-app/date-picker/date-picker-demo.scss b/src/demo-app/date-picker/date-picker-demo.scss new file mode 100644 index 000000000000..4b42f8325a77 --- /dev/null +++ b/src/demo-app/date-picker/date-picker-demo.scss @@ -0,0 +1,9 @@ +.demo-basic { + padding: 0; +} +.demo-card { + margin: 16px; +} +.demo-basic md-card-content { + padding: 16px; +} diff --git a/src/demo-app/date-picker/date-picker-demo.ts b/src/demo-app/date-picker/date-picker-demo.ts new file mode 100644 index 000000000000..52d285a9e4d7 --- /dev/null +++ b/src/demo-app/date-picker/date-picker-demo.ts @@ -0,0 +1,15 @@ +import {Component} from '@angular/core'; + +@Component({ + moduleId: module.id, + selector: 'date-pĂ­cker-demo', + templateUrl: 'date-picker-demo.html', + styleUrls: ['date-picker-demo.css'], +}) +export class DatePickerDemo { + date: any = new Date(Date.now() + 60 * 60 * 24 * 15 * 1000); + date01: any = new Date(Date.now() + 60 * 60 * 24 * 15 * 1000); + date02: any = new Date(Date.now() + 60 * 60 * 24 * 18 * 1000); + ini: any = new Date(Date.now() + 60 * 60 * 24 * 9 * 1000); + end: any = new Date(Date.now() + 60 * 60 * 24 * 18 * 1000); +} diff --git a/src/lib/date-picker/README.md b/src/lib/date-picker/README.md new file mode 100644 index 000000000000..7f4e5013719d --- /dev/null +++ b/src/lib/date-picker/README.md @@ -0,0 +1,37 @@ +# MdDatePicker +Basic Date Picker Component. +> The `` component fully support two-way binding of `ngModel`. +#### Format +```js +export class DatePickerDemo { + date: any = new Date(Date.now()+60*60*24*15*1000); +} +``` + +## Basic +```html + + + +``` + + +## Two selection basic +```html + + + + +{{ _date2.Days }} +``` + + +## Two selection complete + +```html + + + + +{{ _date3.Days }} +``` diff --git a/src/lib/date-picker/_date-picker-theme.scss b/src/lib/date-picker/_date-picker-theme.scss new file mode 100644 index 000000000000..91d1e89cb705 --- /dev/null +++ b/src/lib/date-picker/_date-picker-theme.scss @@ -0,0 +1,52 @@ +@import '../core/theming/palette'; +@import '../core/theming/theming'; + +@mixin _md-date-picker-color($palette) { + ._top { + background: md-color($palette, 700); + } + ._days_selected { + ._background { + background-color: md-color($palette, 0.2) !important; + } + span { + color: md-color($palette, 500); + } + } + ._today { + z-index: 1; + span { + color: md-color($palette, 500); + } + } + ._day:not(._focused):hover { + ._background { + background: md-color($palette, 200) !important; + } + span { + color: #fff; + } + } + ._day._focused { + ._background { + background: md-color($palette, 500) !important; + } + span { + color: #fff; + } + } +} +@mixin md-date-picker-theme($theme) { + $primary: map-get($theme, primary); + $accent: map-get($theme, accent); + $warn: map-get($theme, warn); + .primary { + @include _md-date-picker-color($primary); + } + .accent { + @include _md-date-picker-color($accent); + } + .warn { + @include _md-date-picker-color($warn); + } +} diff --git a/src/lib/date-picker/date-picker.html b/src/lib/date-picker/date-picker.html new file mode 100644 index 000000000000..f4f6c2dc879f --- /dev/null +++ b/src/lib/date-picker/date-picker.html @@ -0,0 +1,101 @@ +
+
+ +
+ +
diff --git a/src/lib/date-picker/date-picker.scss b/src/lib/date-picker/date-picker.scss new file mode 100644 index 000000000000..86f75dd1a12b --- /dev/null +++ b/src/lib/date-picker/date-picker.scss @@ -0,0 +1,179 @@ +:host { + display: inline-block; + position: relative; +} +._top { + padding: 20px; + ._top_year { + font-size: 16px; + color: #fff; + } + ._top_date { + font-size: 36px; + color: #fff; + } +} +._focusedPicker { + opacity: 1 !important; + transform: scaleY(1) !important; +} +._bg { + background: #fff; +} +._datePicker-content { + position: relative; + display: inline-block; + float: left; + ._header { + padding: 4px 16px; + } + ._days { + padding: 8px 16px; + } +} +._control { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + display: flex; + justify-content: space-between; + position: relative; + cursor: default; + div { + position: absolute; + top: 0; + text-align: center; + width: 100%; + opacity: 0.7; + left: 0; + padding: 4px; + } + span { + position: relative; + display: flex; + cursor: pointer; + } +} +._datePicker { + width: 312px; + background: transparent; + box-shadow: rgba(0, 0, 0, 0.117647) 0 1px 6px, rgba(0, 0, 0, 0.117647) 0 1px 4px; + z-index: 66; + transition: transform 450ms cubic-bezier(0.23, 1, 0.32, 1) 0ms, opacity 450ms cubic-bezier(0.23, 1, 0.32, 1) 0ms; + transform-origin: left top 0; + opacity: 0; + transform: scaleY(0); + border-radius: 4px; + overflow: hidden; + &._dual { + width: 640px; + ._top { + ._top_date, ._top_year { + text-align: center; + } + } + } +} +._days { + cursor: default; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + width: 320px; + box-sizing: border-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-flex-wrap: wrap; + -ms-flex-wrap: wrap; + flex-wrap: wrap; +} +._DaysName { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + pointer-events: none; + width: 36px; + height: 36px; + display: inline-block; + text-align: center; + line-height: 36px; + opacity: 0.39; + text-transform: uppercase; + font-size: 13px; + margin: 2px; +} +._before { + opacity: 1; +} +._today { + z-index: 1; +} +@keyframes stateSELECT { + 0% { + opacity: 0.6; + //box-shadow: 0 0 0 0 #00bcd4; + } + 75% { + opacity: 1; + //box-shadow: 0 0 0 16px rgba(255, 255, 255, 0); + } +} +._parent_S { + ._background { + animation: 1200ms stateSELECT infinite; + transition: cubic-bezier(0.23, 1, 0.32, 1); + } +} +._day, ._focused { + width: 40px; + height: 40px; + display: inline-block; + position: relative; + line-height: 40px; + text-align: center; + font-size: 13px; + ._background { + content: ''; + position: absolute; + top: 2px; + bottom: 2px; + left: 2px; + right: 2px; + margin: auto; + border-radius: 100%; + pointer-events: none; + } + span { + width: inherit; + height: inherit; + position: absolute; + left: 0; + top: 0; + outline: none; + cursor: pointer; + opacity: 0.87; + div { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + } + } +} + +._picker { + pointer-events: auto; + cursor: text; + outline: none; + ._input { + pointer-events: none !important; + } +} +._focused { + //opacity: 0.1; +} diff --git a/src/lib/date-picker/date-picker.ts b/src/lib/date-picker/date-picker.ts new file mode 100644 index 000000000000..1c36f3a98200 --- /dev/null +++ b/src/lib/date-picker/date-picker.ts @@ -0,0 +1,327 @@ +import { + Component, + ElementRef, + forwardRef, + NgModule, + Input, + Output, + SimpleChange, + OnChanges, + AfterContentInit, + EventEmitter, + ModuleWithProviders, + ViewChild, + ViewContainerRef, + ViewChildren, + QueryList, +} from '@angular/core'; +import { + NG_VALUE_ACCESSOR, + ControlValueAccessor, + FormsModule, +} from '@angular/forms'; +import { CommonModule } from '@angular/common'; +import { + Overlay, + OverlayModule, + OverlayState, + OverlayOrigin, + Portal, + PortalModule, + TemplatePortalDirective, +} from '../core'; + +const noop = () => {}; + +export const MD_PICKER_CONTROL_VALUE_ACCESSOR: any = { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => DatePicker), + multi: true +}; + +@Component({ + moduleId: module.id, + selector: 'md-date-picker', + styleUrls: ['date-picker.css'], + templateUrl: 'date-picker.html', + host: { + '[class]': '_color' + }, + providers: [MD_PICKER_CONTROL_VALUE_ACCESSOR], +}) +export class DatePicker implements ControlValueAccessor, AfterContentInit, OnChanges { + public _Date: string = `${new Date()}`; + stateSELECT: boolean = false; + dateNow: any = new Date(); + dayActive: any; + dayActive2: any; + days: any = []; + days2: any = []; + date2INT: any = Date.now(); + dateINI: any; + dateEND: any; + dateINT: any; + dateToday: any; + _focused: boolean = false; + _mode: boolean = false; + _color: string = 'primary'; + daysName: Array = [ + 'm', + 't', + 'w', + 't', + 'f', + 's', + 's', + ]; + _value: any = ''; + @ViewChildren(TemplatePortalDirective) templatePortals: QueryList>; + @ViewChild(OverlayOrigin) _overlayOrigin: OverlayOrigin; + openPanelWithBackdrop() { + let config = new OverlayState(); + + config.positionStrategy = this.overlay.position() + .global() + .centerHorizontally() + .centerVertically(); + config.hasBackdrop = true; + + let overlayRef = this.overlay.create(config); + overlayRef.attach(this.templatePortals.first); + overlayRef.backdropClick().subscribe(() => overlayRef.detach()); + } + @Input() + set mode(v: string) { + if (v == 'dual') { + this._mode = true; + }else { + this._mode = false; + } + } + @Input() + set date2(v: any) { + if (v !== this.days2) { + this.days2 = this.Month(v); + this.date2INT = new Date(v).getTime(); + } + } + @Output() date2Change: EventEmitter = new EventEmitter(); + + @Input() + get color(): string { + return this._color; + } + + set color(value: string) { + this._updateColor(value); + } + _updateColor(newColor: string) { + this._color = newColor; + } + constructor( + private elementRef: ElementRef, + public overlay: Overlay, + public viewContainerRef: ViewContainerRef + ) { + + } + + _handleClick() { + let selector: any = this.elementRef.nativeElement.querySelector('._picker'); + let _DatePicker = this.elementRef.nativeElement.querySelector('._datePicker'); + if (_DatePicker != null) { + _DatePicker.setAttribute('style', ` + top: ${selector.offsetHeight}px + `); + this._focused = true; + + } + } + + /** + * OutFocus. + * TODO: internal + */ + _handleOutFocus(state: boolean) { + this._focused = false; + + } + + registerOnChange(fn: any) { + this._onChangeCallback = fn; + } + + /** + * Implemented as part of ControlValueAccessor. + * TODO: internal + */ + registerOnTouched(fn: any) { + this._onTouchedCallback = fn; + } + + /** Callback registered via registerOnTouched (ControlValueAccessor) */ + private _onTouchedCallback: () => void = noop; + + /** Callback registered via registerOnChange (ControlValueAccessor) */ + private _onChangeCallback: (_: any) => void = noop; + + get value(): any { + return this._value; + }; + + @Input() set value(v: any) { + if (v !== this._value) { + this._value = v; + this._onChangeCallback(v); + } + } + + writeValue(value: any) { + this.selectDate(value, false); + this.getMonth(value); + this._value = value; + } + + private INT_DATE(date: any) { + return new Date(date).getTime(); + } + + selectDate(date: any, _for: any = false, e$: any = false) { + let dateSelected = new Date(date); + let selector = this.elementRef.nativeElement.querySelector('._picker'); + if (this.stateSELECT == true) { + if (e$ != false) { + this.date2 = dateSelected; + this.date2Change.emit(dateSelected); + selector.focus(); + } + this.dayActive2 = `${ + dateSelected.getFullYear() + }+${ + dateSelected.getMonth() + }+${ + dateSelected.getDate() + }`; + }else { + this.dayActive = `${ + dateSelected.getFullYear() + }+${ + dateSelected.getMonth() + }+${ + dateSelected.getDate() + }`; + this.value = dateSelected; + this._value = dateSelected; + this._onTouchedCallback(); + } + this._Date = `${ + new Date(date).getDate() + }-${ + new Date(date).getMonth() + 1 + }-${ + new Date(date).getFullYear() + }`; + this.dateINT = Date.now(); + this.dateToday = `${ + new Date().getFullYear() + }+${ + new Date().getMonth() + }+${ + new Date().getDate() + }`; + } + + /** + * _left. + */ + _left(_for: boolean, date: any) { + if (_for == false) { + this.days = this.Month(date._INI - 60 * 60 * 24 * 1000); + }else { + this.days2 = this.Month(date._INI - 60 * 60 * 24 * 1000); + } + } + + /** + * Month prev. + */ + _right(_for: boolean, date: any) { + if (_for == false) { + this.days = this.Month(date._INI.getTime() + (date.dateEND + 2) * 60 * 60 * 24 * 1000); + }else { + this.days2 = this.Month(date._INI.getTime() + (date.dateEND + 2) * 60 * 60 * 24 * 1000); + } + } + + ngAfterContentInit() { + this.stateSELECT = true; + this._handleClick(); + this._focused = false; + this.selectDate(this.date2INT, true); + this.stateSELECT = false; + } + + getMonth(dateSelected: any) { + this.days = this.Month(dateSelected); + } + get Days() { + return ((-this.INT_DATE(this._value) + this.INT_DATE(this.date2INT)) / 60 / 60 / 24 / 1000) + 1; + } + Month(date: any) { + let _days: any = { + data: [], + _INI: '', + dateEND: '', + }; + let dateSelected = new Date(date); + let dayNow = (dateSelected.getDate() - 1) * 60 * 60 * 24 * 1000; + let dateNow = new Date(dateSelected.getTime()); + let dateINI = new Date(dateNow.getTime() - dayNow); + let dateEND: any; + let dayLeft = 0; + if (new Date(dateINI).getDay() == 0) { + dayLeft = 6; + }else { + dayLeft = new Date(dateINI).getDay() - 1; + } + for (var i = 0; i < dayLeft; i++) { + _days.data.push({ + index: null, + date: 0, + }); + } + let dateTemp: any; + for (var _i = 1; _i < 32; _i++) { + dateTemp = new Date((dateINI.getTime()) + ((_i - 1) * 60 * 60 * 24 * 1000)); + if (_i == dateTemp.getDate()) { + dateEND = _i; + _days.data.push({ + index: _i, + date: dateTemp.getTime(), + dateActive: `${dateTemp.getFullYear()}+${dateTemp.getMonth()}+${dateTemp.getDate()}`, + }); + } + } + this.dateINI = dateINI; + _days._INI = dateINI; + _days.dateEND = dateEND; + return _days; + } + ngOnChanges(changes: {[key: string]: SimpleChange}) { + // *** + } +} + +@NgModule({ + imports: [OverlayModule, PortalModule, CommonModule, FormsModule], + exports: [DatePicker], + declarations: [DatePicker], +}) +export class MdDatePickerModule { + static forRoot(): ModuleWithProviders { + return { + ngModule: MdDatePickerModule, + providers: [], + }; + } +} diff --git a/src/lib/date-picker/index.ts b/src/lib/date-picker/index.ts new file mode 100644 index 000000000000..e5ce37c6742d --- /dev/null +++ b/src/lib/date-picker/index.ts @@ -0,0 +1 @@ +export * from './date-picker';