Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[breaking] refactor: Datepicker simple/range/single #2823

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
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
149 changes: 69 additions & 80 deletions src/datepicker-input/datepicker-input.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,101 +5,92 @@ import {
EventEmitter,
ElementRef,
TemplateRef,
ViewChild
ViewChild, HostBinding
} from "@angular/core";
import { NG_VALUE_ACCESSOR } from "@angular/forms";

@Component({
selector: "cds-date-picker-input, ibm-date-picker-input",
template: `
<div class="cds--form-item">
<div class="cds--date-picker"
<label
*ngIf="label"
[for]="id"
class="cds--label"
[ngClass]="{'cds--label--disabled': disabled}">
<ng-container *ngIf="!isTemplate(label)">{{label}}</ng-container>
<ng-template *ngIf="isTemplate(label)" [ngTemplateOutlet]="label"></ng-template>
</label>
<div class="cds--date-picker-input__wrapper"
[ngClass]="{
'cds--date-picker--simple' : type === 'simple',
'cds--date-picker--single' : type === 'single',
'cds--date-picker--range' : type === 'range',
'cds--date-picker--light' : theme === 'light',
'cds--skeleton' : skeleton
'cds--date-picker-input__wrapper--invalid': invalid,
'cds--date-picker-input__wrapper--warn': warn
}">
<div class="cds--date-picker-container">
<label
*ngIf="label"
[for]="id"
class="cds--label"
[ngClass]="{'cds--label--disabled': disabled}">
<ng-container *ngIf="!isTemplate(label)">{{label}}</ng-container>
<ng-template *ngIf="isTemplate(label)" [ngTemplateOutlet]="label"></ng-template>
</label>
<div class="cds--date-picker-input__wrapper"
<span>
<input
#input
*ngIf="!skeleton"
autocomplete="off"
type="text"
class="cds--date-picker__input"
[ngClass]="{
'cds--date-picker-input__wrapper--invalid': invalid,
'cds--date-picker-input__wrapper--warn': warn
}">
<span>
<input
#input
*ngIf="!skeleton"
autocomplete="off"
type="text"
class="cds--date-picker__input"
[ngClass]="{
'cds--date-picker__input--sm': size === 'sm',
'cds--date-picker__input--md': size === 'md',
'cds--date-picker__input--lg': size === 'lg'
}"
[attr.data-invalid]="invalid ? true : undefined"
[value]="value"
[pattern]="pattern"
[placeholder]="placeholder"
[id]= "id"
[disabled]="disabled"
(change)="onChange($event)"/>
<svg
*ngIf="type !== 'simple' && !warn && !invalid"
cdsIcon="calendar"
size="16"
class="cds--date-picker__icon">
</svg>
<svg
*ngIf="invalid"
class="cds--date-picker__icon cds--date-picker__icon--invalid"
cdsIcon="warning--filled"
size="16">
</svg>
<svg
*ngIf="!invalid && warn"
cdsIcon="warning--alt--filled"
size="16"
class="cds--date-picker__icon cds--date-picker__icon--warn">
</svg>
</span>
</div>
<div
*ngIf="helperText && !invalid && !warn"
class="cds--form__helper-text"
[ngClass]="{'cds--form__helper-text--disabled': disabled}">
<ng-container *ngIf="!isTemplate(helperText)">{{helperText}}</ng-container>
<ng-template *ngIf="isTemplate(helperText)" [ngTemplateOutlet]="helperText"></ng-template>
</div>
<div *ngIf="invalid" class="cds--form-requirement">
<ng-container *ngIf="!isTemplate(invalidText)">{{invalidText}}</ng-container>
<ng-template *ngIf="isTemplate(invalidText)" [ngTemplateOutlet]="invalidText"></ng-template>
</div>
<div *ngIf="!invalid && warn" class="cds--form-requirement">
<ng-container *ngIf="!isTemplate(warnText)">{{warnText}}</ng-container>
<ng-template *ngIf="isTemplate(warnText)" [ngTemplateOutlet]="warnText"></ng-template>
</div>
</div>
'cds--date-picker__input--sm': size === 'sm',
'cds--date-picker__input--md': size === 'md',
'cds--date-picker__input--lg': size === 'lg'
}"
[attr.data-invalid]="invalid ? true : undefined"
[value]="value"
[pattern]="pattern"
[placeholder]="placeholder"
[id]= "id"
[disabled]="disabled"
(change)="onChange($event)"
/>
<svg
*ngIf="type !== 'simple' && !warn && !invalid"
cdsIcon="calendar"
size="16"
class="cds--date-picker__icon">
</svg>
<svg
*ngIf="invalid"
class="cds--date-picker__icon cds--date-picker__icon--invalid"
cdsIcon="warning--filled"
size="16">
</svg>
<svg
*ngIf="!invalid && warn"
cdsIcon="warning--alt--filled"
size="16"
class="cds--date-picker__icon cds--date-picker__icon--warn">
</svg>
</span>
</div>
<div
*ngIf="helperText && !invalid && !warn"
class="cds--form__helper-text"
[ngClass]="{'cds--form__helper-text--disabled': disabled}">
<ng-container *ngIf="!isTemplate(helperText)">{{helperText}}</ng-container>
<ng-template *ngIf="isTemplate(helperText)" [ngTemplateOutlet]="helperText"></ng-template>
</div>
<div *ngIf="invalid" class="cds--form-requirement">
<ng-container *ngIf="!isTemplate(invalidText)">{{invalidText}}</ng-container>
<ng-template *ngIf="isTemplate(invalidText)" [ngTemplateOutlet]="invalidText"></ng-template>
</div>
<div *ngIf="!invalid && warn" class="cds--form-requirement">
<ng-container *ngIf="!isTemplate(warnText)">{{warnText}}</ng-container>
<ng-template *ngIf="isTemplate(warnText)" [ngTemplateOutlet]="warnText"></ng-template>
</div>
</div>
`,
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: DatePickerInput,
multi: true
}
]
],
host: {
"class": 'cds--date-picker-container'
}
})
export class DatePickerInput {
private static datePickerCount = 0;
Expand All @@ -111,8 +102,6 @@ export class DatePickerInput {

@Input() id = `datepicker-${DatePickerInput.datePickerCount++}`;

@Input() hasIcon = false;

@Input() label: string | TemplateRef<any>;

@Input() placeholder = "mm/dd/yyyy";
Expand Down
111 changes: 52 additions & 59 deletions src/datepicker/datepicker.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,54 +58,50 @@ if (languages.default?.default["en"]?.weekdays) {
<div
class="cds--date-picker"
[ngClass]="{
'cds--date-picker--range' : range,
'cds--date-picker--single' : !range,
'cds--date-picker--simple' : datePickerType === 'simple',
'cds--date-picker--range' : datePickerType === 'range',
'cds--date-picker--single' : datePickerType === 'single',
'cds--date-picker--light' : theme === 'light',
'cds--skeleton' : skeleton
}">
<div class="cds--date-picker-container">
<cds-date-picker-input
#input
[label]="label"
[placeholder]="placeholder"
[pattern]="inputPattern"
[id]="id + '-input'"
[size]="size"
[type]="(range ? 'range' : 'single')"
[hasIcon]="(range ? false : true)"
[disabled]="disabled"
[invalid]="invalid"
[invalidText]="invalidText"
[warn]="warn"
[warnText]="warnText"
[skeleton]="skeleton"
[helperText]="helperText"
(valueChange)="onValueChange($event)"
(click)="openCalendar(input)">
</cds-date-picker-input>
</div>

<div *ngIf="range" class="cds--date-picker-container">
<cds-date-picker-input
#rangeInput
[label]="rangeLabel"
[placeholder]="placeholder"
[pattern]="inputPattern"
[id]="id + '-rangeInput'"
[size]="size"
[type]="(range ? 'range' : 'single')"
[hasIcon]="(range ? true : null)"
[disabled]="disabled"
[invalid]="rangeInvalid"
[invalidText]="rangeInvalidText"
[warn]="rangeWarn"
[warnText]="rangeWarnText"
[skeleton]="skeleton"
[helperText]="rangeHelperText"
(valueChange)="onRangeValueChange($event)"
(click)="openCalendar(rangeInput)">
</cds-date-picker-input>
</div>
<cds-date-picker-input
#input
[label]="label"
[placeholder]="placeholder"
[pattern]="inputPattern"
[id]="id + '-input'"
[size]="size"
[type]="datePickerType"
[disabled]="disabled"
[invalid]="invalid"
[invalidText]="invalidText"
[warn]="warn"
[warnText]="warnText"
[skeleton]="skeleton"
[helperText]="helperText"
(valueChange)="onValueChange($event)"
(click)="openCalendar(input)">
</cds-date-picker-input>

<cds-date-picker-input
*ngIf="datePickerType === 'range'"
#rangeInput
[label]="rangeLabel"
[placeholder]="placeholder"
[pattern]="inputPattern"
[id]="id + '-rangeInput'"
[size]="size"
type="range"
[disabled]="disabled"
[invalid]="rangeInvalid"
[invalidText]="rangeInvalidText"
[warn]="rangeWarn"
[warnText]="rangeWarnText"
[skeleton]="skeleton"
[helperText]="rangeHelperText"
(valueChange)="onRangeValueChange($event)"
(click)="openCalendar(rangeInput)">
</cds-date-picker-input>
</div>
</div>
`,
Expand All @@ -126,10 +122,7 @@ export class DatePicker implements
AfterViewInit {
private static datePickerCount = 0;

/**
* Select calendar range mode
*/
@Input() range = false;
@Input() datePickerType: "simple" | "single" | "range" = "simple";

/**
* Format of date
Expand Down Expand Up @@ -228,11 +221,11 @@ export class DatePicker implements
}
get flatpickrOptions(): Partial<Options> {
const plugins = [...this.plugins, carbonFlatpickrMonthSelectPlugin];
if (this.range) {
if (this.datePickerType === "range") {
plugins.push(rangePlugin({ input: `#${this.id}-rangeInput`, position: "left" }));
}
return Object.assign({}, this._flatpickrOptions, this.flatpickrBaseOptions, {
mode: this.range ? "range" : "single",
mode: this.datePickerType === "range" ? "range" : "single",
plugins,
dateFormat: this.dateFormat,
locale: languages.default?.default[this.language] || languages.default[this.language]
Expand Down Expand Up @@ -268,7 +261,7 @@ export class DatePicker implements
onClose: (date) => {
// This makes sure that the `flatpickrInstance selectedDates` are in sync with the values of
// the inputs when the calendar closes.
if (this.range && this.flatpickrInstance) {
if (this.datePickerType === "range" && this.flatpickrInstance) {
const inputValue = this.input.input.nativeElement.value;
const rangeInputValue = this.rangeInput.input.nativeElement.value;
if (inputValue || rangeInputValue) {
Expand Down Expand Up @@ -332,7 +325,7 @@ export class DatePicker implements
// and because we rely on a library that operates outside the Angular view of the world
// we need to keep trying to load the library, until the relevant DOM is actually live
ngAfterViewChecked() {
if (!this.isFlatpickrLoaded()) {
if (this.datePickerType !== "simple" && !this.isFlatpickrLoaded()) {
// @ts-ignore ts is unhappy with the below call to `flatpickr`
this.flatpickrInstance = flatpickr(`#${this.id}-input`, this.flatpickrOptions);
// if (and only if) the initialization succeeded, we can set the date values
Expand All @@ -348,7 +341,7 @@ export class DatePicker implements
onFocus() {
// Updates the month manually when calendar mode is range because month
// will not update properly without manually updating them on focus.
if (this.range) {
if (this.datePickerType === "range") {
if (this.rangeInput.input.nativeElement === document.activeElement && this.flatpickrInstance.selectedDates[1]) {
const currentMonth = this.flatpickrInstance.selectedDates[1].getMonth();
this.flatpickrInstance.changeMonth(currentMonth, false);
Expand Down Expand Up @@ -414,7 +407,7 @@ export class DatePicker implements
onValueChange(event: string) {
if (this.isFlatpickrLoaded()) {
const date = this.flatpickrInstance.parseDate(event, this.dateFormat);
if (this.range) {
if (this.datePickerType === "range") {
this.setDateValues([date, this.flatpickrInstance.selectedDates[1]]);
} else {
this.setDateValues([date]);
Expand All @@ -438,7 +431,7 @@ export class DatePicker implements
* Handles opening the calendar "properly" when the calendar icon is clicked.
*/
openCalendar(datepickerInput: DatePickerInput) {
if (this.range) {
if (this.datePickerType === "range") {
datepickerInput.input.nativeElement.click();

// If the first input's calendar icon is clicked when calendar is in range mode, then
Expand Down Expand Up @@ -469,7 +462,7 @@ export class DatePicker implements
* Handles the initialization of event listeners for the datepicker input and range input fields.
*/
protected addInputListeners() {
if (!this.isFlatpickrLoaded()) {
if (this.datePickerType === "simple" || !this.isFlatpickrLoaded()) {
return;
}

Expand Down Expand Up @@ -520,7 +513,7 @@ export class DatePicker implements
* @param newDates An optional SimpleChange of date values
*/
protected resetFlatpickrInstance(newDates?: SimpleChange) {
if (this.isFlatpickrLoaded()) {
if (this.datePickerType !== "simple" && this.isFlatpickrLoaded()) {
let dates = this.flatpickrInstance.selectedDates;
if (newDates && this.didDateValueChange(newDates.currentValue, newDates.previousValue)) {
dates = newDates.currentValue;
Expand Down Expand Up @@ -646,7 +639,7 @@ export class DatePicker implements
// In range mode, if a date is selected from the first calendar that is from the previous month,
// the month will not be updated on the calendar until the calendar is re-opened.
// This will make sure the calendar is updated with the correct month.
if (this.range && this.flatpickrInstance.selectedDates[0]) {
if (this.datePickerType === "range" && this.flatpickrInstance.selectedDates[0]) {
const currentMonth = this.flatpickrInstance.selectedDates[0].getMonth();

// `flatpickrInstance.changeMonth` removes the focus on the selected date element and will
Expand Down
Loading
Loading