Skip to content

Commit

Permalink
refactor: refactor min, max, value with clamping and update tests
Browse files Browse the repository at this point in the history
  • Loading branch information
motss committed Oct 3, 2021
1 parent 1179798 commit 14915a0
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 91 deletions.
125 changes: 66 additions & 59 deletions src/date-picker/date-picker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import { calendar } from 'nodemod/dist/calendar/calendar.js';
import { getWeekdays } from 'nodemod/dist/calendar/helpers/get-weekdays.js';
import { toUTCDate } from 'nodemod/dist/calendar/helpers/to-utc-date.js';

import { calendarViews,MAX_DATE } from '../constants.js';
import { adjustOutOfRangeValue } from '../helpers/adjust-out-of-range-value.js';
import { calendarViews, DateTimeFormat, MAX_DATE } from '../constants.js';
import { clampValue } from '../helpers/clamp-value.js';
import { dateValidator } from '../helpers/date-validator.js';
import { dispatchCustomEvent } from '../helpers/dispatch-custom-event.js';
import { focusElement } from '../helpers/focus-element.js';
Expand Down Expand Up @@ -41,18 +41,15 @@ export class DatePicker extends DatePickerMixin(DatePickerMinMaxMixin(LitElement
@state()
private _currentDate: Date;

@state()
private _hasMax!: boolean;
// @state()
// private _hasMax!: boolean;

@state()
private _hasMin!: boolean;
// @state()
// private _hasMin!: boolean;

@state()
private _max: Date;

@state()
private _maxDate!: Date;

@state()
private _min: Date;

Expand Down Expand Up @@ -98,68 +95,78 @@ export class DatePicker extends DatePickerMixin(DatePickerMinMaxMixin(LitElement

public override willUpdate(changedProperties: DatePickerChangedProperties): void {
if (changedProperties.has('locale')) {
this.#formatters = toFormatters(this.locale);
}
const newLocale = (
this.locale || DateTimeFormat().resolvedOptions().locale
) as string;

if (changedProperties.has('startView')) {
const oldStartView = changedProperties.get('startView') as CalendarView;
const newStartView = this.startView;

if (!calendarViews.includes(newStartView)) {
this.startView = this.startView = oldStartView;
}
this.#formatters = toFormatters(newLocale);
this.locale = newLocale;
}

if (changedProperties.has('value')) {
const oldValue = toResolvedDate(
changedProperties.get('value') as string || this._TODAY_DATE
if (
(
['max', 'min', 'value'] as (keyof Pick<DatePickerProperties, 'max' | 'min' | 'value'>)[]
).some(n => changedProperties.has(n))
) {
const todayDate = this._TODAY_DATE;
const oldMin =
toResolvedDate((changedProperties.get('min') || this.min || todayDate) as MaybeDate);
const oldMax =
toResolvedDate((changedProperties.get('max') || this.max || MAX_DATE) as MaybeDate);
const oldValue =
toResolvedDate((changedProperties.get('value') || this.value || todayDate) as MaybeDate);

// FIXME: Can look into use MAX_DATE as fallback
const newMin = dateValidator(this.min as MaybeDate, oldMin);
const newMax = dateValidator(this.max as MaybeDate, oldMax);
const newValue = dateValidator(this.value as MaybeDate, oldValue);

/**
* NOTE: Ensure new `value` is clamped between new `min` and `max` as `newValue` will only
* contain valid date but its value might be a out-of-range date.
*/
const valueDate = toResolvedDate(
clampValue(+newMin.date, +newMax.date, +newValue.date)
);
const { date } = dateValidator(this.value, oldValue);

this._currentDate = new Date(date);
this._selectedDate = new Date(date);
this.valueAsDate = new Date(date);
this.valueAsNumber = +date;
}
this._min = newMin.date;
this._max = newMax.date;

const hasMax = changedProperties.has('max');
const hasMin = changedProperties.has('min');
// this._hasMin = newMin.isValid;
// this._hasMax = newMax.isValid;

if (hasMax || hasMin) {
const update = (isMax = false) => {
const oldValue = toResolvedDate(
changedProperties.get(isMax ? 'max' : 'min') as string ||
(isMax ? MAX_DATE : this._TODAY_DATE)
);
const value = this[isMax ? 'max' : 'min'] as MaybeDate;
const { date, isValid } = dateValidator(value, oldValue);

this[isMax ? '_max' : '_min'] = date;
this[isMax ? '_hasMax' : '_hasMin'] = isValid;
};
this._currentDate = new Date(valueDate);
this._selectedDate = new Date(valueDate);
this.valueAsDate = new Date(valueDate);
this.valueAsNumber = +valueDate;
this.value = toDateString(valueDate);
}

if (hasMax) update(true);
if (hasMin) update();
if (changedProperties.has('startView')) {
const oldStartView =
(changedProperties.get('startView') || this.startView) as CalendarView;

/**
* NOTE: Reset to old `startView` to ensure a valid value.
*/
if (!calendarViews.includes(this.startView)) {
this.startView = oldStartView;
}

const min = this._min;
const max = this._max;
const adjustedCurrentDate = adjustOutOfRangeValue(min, max, this._currentDate);
if (this.startView === 'calendar') {
const newSelectedYear = new Date(
clampValue(
+this._min,
+this._max,
+this._selectedDate
)
);

this._currentDate = adjustedCurrentDate;
this._selectedDate = new Date(adjustedCurrentDate);
this.value = toDateString(adjustedCurrentDate);
this._selectedDate = newSelectedYear;
this._currentDate = new Date(newSelectedYear);
}
}

if (changedProperties.has('startView') && this.startView === 'calendar') {
const newSelectedYear = adjustOutOfRangeValue(
this._min,
this._max,
this._selectedDate
);

this._selectedDate = newSelectedYear;
this._currentDate = new Date(newSelectedYear);
}
}

protected override firstUpdated(): void {
Expand Down
8 changes: 8 additions & 0 deletions src/mixins/date-picker-min-max-mixin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,17 @@ export const DatePickerMinMaxMixin = <BaseConstructor extends Constructor<LitEle
): MixinReturnType<BaseConstructor, DatePickerMinMaxProperties> => {
class DatePickerMinMaxClass extends SuperClass implements DatePickerMinMaxProperties {

/**
* NOTE: `null` or `''` will always reset to the old valid date. In order to reset to
* today's date, set `max` undefined.
*/
@property({ reflect: true, converter: { toAttribute: nullishAttributeConverter } })
public max?: string;

/**
* NOTE: `null` or `''` will always reset to the old valid date. In order to reset to
* today's date, set `min` undefined.
*/
@property({ reflect: true, converter: { toAttribute: nullishAttributeConverter } })
public min?: string;
}
Expand Down
4 changes: 4 additions & 0 deletions src/mixins/date-picker-mixin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ export const DatePickerMixin = <BaseConstructor extends Constructor<LitElement>>
@property({ reflect: true, converter: { toAttribute: nullishAttributeConverter } })
public startView: CalendarView = 'calendar';

/**
* NOTE: `null` or `''` will always reset to the old valid date. In order to reset to
* today's date, set `value` undefined.
*/
@property()
public value: string = toDateString(toResolvedDate());

Expand Down
Loading

0 comments on commit 14915a0

Please sign in to comment.