Conversation
…nput; add test for both input modes
There was a problem hiding this comment.
Pull request overview
This pull request adds a new IgcDateRangeInputComponent to enable editable date range input in single-input mode for the date range picker. The implementation involves refactoring the existing IgcDateTimeInputComponent by extracting common functionality into a new IgcDateTimeInputBaseComponent base class that uses generic type parameters to support both single date values and date ranges.
Changes:
- Extracted
IgcDateTimeInputBaseComponentas a generic base class for date/time input components - Created new
IgcDateRangeInputComponentfor editable date range input with mask support - Updated
IgcDateRangePickerComponentto use the new date range input component in single-input mode - Updated story files to document DateRangeValue type (though with incorrect additions to non-date components)
Reviewed changes
Copilot reviewed 18 out of 18 changed files in this pull request and generated 18 comments.
Show a summary per file
| File | Description |
|---|---|
| src/components/date-time-input/date-time-input.base.ts | New generic base class extracted from date-time-input, providing common functionality for date/time inputs |
| src/components/date-time-input/date-time-input.ts | Refactored to extend the new base class, removing duplicate code |
| src/components/date-range-picker/date-range-input.ts | New component implementing editable date range input with mask parsing and formatting |
| src/components/date-range-picker/date-range-picker.ts | Updated to integrate the new date-range-input component and handle its events |
| src/components/date-time-input/date-util.ts | Added DateRangePosition enum and DateRangePart interfaces for range-specific logic |
| src/index.ts | Updated export path for IgcDateTimeInputComponentEventMap |
| stories/*.stories.ts | Updated type definitions (with errors for non-date components) |
| Test files | Updated to use and test the new date-range-input component |
src/components/date-range-picker/date-range-picker-single.spec.ts
Outdated
Show resolved
Hide resolved
b58c49d to
3a366f7
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 21 out of 21 changed files in this pull request and generated 9 comments.
Comments suppressed due to low confidence (1)
src/components/date-range-picker/date-range-picker.ts:809
_handleDateRangeInputChangeEventassumesinput.valueis always non-null (input.value!). After callingclear()(or if the range input emits a change withnull), this will throw when_swapDatesis called. Handle thenullcase explicitly (e.g., setthis.value = nulland emitigcChangeaccordingly), and strongly type the event asCustomEvent<DateRangeValue | null>instead ofany.
protected _handleDateRangeInputChangeEvent(event: CustomEvent<any>) {
event.stopPropagation();
const input = event.target as IgcDateRangeInputComponent;
const newValue = input.value!;
const { start, end } = this._swapDates(newValue) ?? {
start: null,
end: null,
};
this._setCalendarRangeValues();
this.value = { start, end };
this.emitEvent('igcChange', { detail: this.value });
}
| // #region Abstract methods and properties | ||
|
|
||
| protected abstract get _datePartDeltas(): any; | ||
|
|
There was a problem hiding this comment.
IgcDateTimeInputBaseComponent declares protected abstract get _datePartDeltas(): any;. This accessor signature both (1) forces subclasses to implement a getter (but IgcDateRangeInputComponent currently defines _datePartDeltas as a field) which causes a TS override error, and (2) loses type-safety via any. Make this an abstract property with a concrete type (e.g. protected abstract readonly _datePartDeltas: DatePartDeltas;) or keep it as a getter but ensure all subclasses implement it as a getter with DatePartDeltas return type.
| interface IgcFileInputArgs { | ||
| /** | ||
| * The value of the control. | ||
| * Similar to native file input, this property is read-only and cannot be set programmatically. | ||
| */ | ||
| value: string | Date; | ||
| value: string | Date | DateRangeValue; | ||
| /** Gets/Sets the locale used for getting language, affecting resource strings. */ |
There was a problem hiding this comment.
DateRangeValue is referenced in IgcFileInputArgs.value (and in the argTypes string), but it isn’t imported in this file, which will cause a TypeScript compile error. Also, IgcFileInputComponent.value is string-only (read-only), so the story’s value type/options should be updated to match the real API.
| interface IgcDateTimeInputArgs { | ||
| /** The date format to apply on the input. */ | ||
| inputFormat: string; | ||
| /** The value of the input. */ | ||
| value: string | Date; | ||
| value: string | Date | DateRangeValue; | ||
| /** The minimum value required for the input to remain valid. */ |
There was a problem hiding this comment.
DateRangeValue is referenced in IgcDateTimeInputArgs.value (and in the argTypes string), but it isn’t imported in this file, which will fail TypeScript compilation. IgcDateTimeInputComponent.value is Date | null (with string conversion via attribute), so the story should not include DateRangeValue as an option/type.
| @@ -21,7 +22,7 @@ describe('Date Range Picker Single Input - Form integration', () => { | |||
| before(() => defineComponents(IgcDateRangePickerComponent)); | |||
|
|
|||
| let picker: IgcDateRangePickerComponent; | |||
| let input: IgcInputComponent; | |||
| let input: IgcDateRangeInputComponentComponent; | |||
| let startKey = ''; | |||
There was a problem hiding this comment.
The imported type alias IgcDateRangeInputComponentComponent looks accidental and confusing (double “Component”). Prefer importing the type with the actual component name (or using typeof IgcDateRangeInputComponent) to keep the test typings clear.
| protected override _datePartDeltas: DatePartDeltas = { | ||
| date: 1, | ||
| month: 1, | ||
| year: 1, | ||
| }; | ||
|
|
There was a problem hiding this comment.
_datePartDeltas is declared as an instance field here, but the base class (IgcDateTimeInputBaseComponent) defines _datePartDeltas as an abstract getter. This will fail to compile with “cannot override an accessor with a property”. Implement _datePartDeltas as a getter (or adjust the base class contract to be an abstract property) so the override shape matches.
| protected override _datePartDeltas: DatePartDeltas = { | |
| date: 1, | |
| month: 1, | |
| year: 1, | |
| }; | |
| protected readonly _dateRangeDatePartDeltas: DatePartDeltas = { | |
| date: 1, | |
| month: 1, | |
| year: 1, | |
| }; | |
| protected override get _datePartDeltas(): DatePartDeltas { | |
| return this._dateRangeDatePartDeltas; | |
| } |
| export interface IgcDateTimeInputComponentEventMap extends Omit< | ||
| IgcInputComponentEventMap, | ||
| 'igcChange' | ||
| > { | ||
| igcChange: CustomEvent<Date | DateRangeValue | null>; | ||
| } |
There was a problem hiding this comment.
IgcDateTimeInputComponentEventMap now types igcChange as CustomEvent<Date | DateRangeValue | null>. This makes the exported event map for igc-date-time-input too broad (it never emits DateRangeValue) and also makes igc-date-range-input appear to emit Date values. Consider making the base class generic over the igcChange detail type (separate event maps per component, or a generic IgcDateTimeInputEventMap<TValue>), so each component has accurate event typings.
| * Emits the input event after user interaction. | ||
| */ | ||
| protected _emitInputEvent(): void { | ||
| this._setTouchedState(); | ||
| this.emitEvent('igcInput', { detail: this.value?.toString() }); |
There was a problem hiding this comment.
_emitInputEvent() emits igcInput with detail: this.value?.toString(). For IgcDateRangeInputComponent, value is an object, so this produces "[object Object]" rather than the actual text the user typed. Consider emitting the current input text (this._maskedValue) for igcInput, or provide an overridable formatter so each derived component can emit a meaningful string.
| * Emits the input event after user interaction. | |
| */ | |
| protected _emitInputEvent(): void { | |
| this._setTouchedState(); | |
| this.emitEvent('igcInput', { detail: this.value?.toString() }); | |
| * Returns the string detail to emit with the `igcInput` event. | |
| * The default implementation prefers the masked value (what the user sees), | |
| * and falls back to the underlying value's string representation. | |
| * Derived components can override this to provide a more specific format. | |
| */ | |
| // eslint-disable-next-line @typescript-eslint/no-unused-vars | |
| protected _getInputEventDetail(): string | undefined { | |
| if (this._maskedValue != null) { | |
| return this._maskedValue; | |
| } | |
| return this.value != null ? this.value.toString() : undefined; | |
| } | |
| /** | |
| * Emits the input event after user interaction. | |
| */ | |
| protected _emitInputEvent(): void { | |
| this._setTouchedState(); | |
| this.emitEvent('igcInput', { detail: this._getInputEventDetail() }); |
| interface IgcInputArgs { | ||
| /** The value of the control. */ | ||
| value: string | Date; | ||
| value: string | Date | DateRangeValue; |
There was a problem hiding this comment.
DateRangeValue is referenced in IgcInputArgs.value (and in the argTypes string), but it is not imported in this file, which will cause a TypeScript compile error. Also, IgcInputComponent.value is string (not DateRangeValue), so the story’s value type/options should be corrected to reflect the actual component API.
| value: string | Date | DateRangeValue; | |
| value: string; |
| * Regardless of the currently set `value-mode`, an empty value will return an empty string. | ||
| */ | ||
| value: string | Date; | ||
| value: string | Date | DateRangeValue; |
There was a problem hiding this comment.
DateRangeValue is referenced in IgcMaskInputArgs.value (and in the argTypes string), but it isn’t imported in this file, which will fail TypeScript compilation. Additionally, IgcMaskInputComponent.value is a string, so the story’s value type/options should not advertise Date/DateRangeValue unless the component actually supports those types.
| value: string | Date | DateRangeValue; | |
| value: string; |
Closes #2114
Adds a new
IgcDateRangeInputComponentto be used by theIgcDateRangePicker, which would allow to edit date range by typing in singe-input mode as well.