Skip to content

Add editable date range input#1733

Draft
ddaribo wants to merge 24 commits intomasterfrom
bpachilova/range-editable-date-input
Draft

Add editable date range input#1733
ddaribo wants to merge 24 commits intomasterfrom
bpachilova/range-editable-date-input

Conversation

@ddaribo
Copy link
Contributor

@ddaribo ddaribo commented Jun 9, 2025

Closes #2114
Adds a new IgcDateRangeInputComponent to be used by the IgcDateRangePicker, which would allow to edit date range by typing in singe-input mode as well.

drp-editable

@ddaribo ddaribo requested a review from rkaraivanov June 9, 2025 13:15
@rkaraivanov rkaraivanov added enhancement New feature or request date-range-picker labels Jun 10, 2025
@ddaribo ddaribo marked this pull request as ready for review July 15, 2025 06:58
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 IgcDateTimeInputBaseComponent as a generic base class for date/time input components
  • Created new IgcDateRangeInputComponent for editable date range input with mask support
  • Updated IgcDateRangePickerComponent to 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

@ddaribo ddaribo force-pushed the bpachilova/range-editable-date-input branch from b58c49d to 3a366f7 Compare February 20, 2026 12:53
@ddaribo ddaribo marked this pull request as draft February 20, 2026 14:09
@ddaribo ddaribo mentioned this pull request Feb 26, 2026
5 tasks
@ddaribo ddaribo linked an issue Mar 5, 2026 that may be closed by this pull request
5 tasks
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

  • _handleDateRangeInputChangeEvent assumes input.value is always non-null (input.value!). After calling clear() (or if the range input emits a change with null), this will throw when _swapDates is called. Handle the null case explicitly (e.g., set this.value = null and emit igcChange accordingly), and strongly type the event as CustomEvent<DateRangeValue | null> instead of any.
  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 });
  }

Comment on lines +460 to +463
// #region Abstract methods and properties

protected abstract get _datePartDeltas(): any;

Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Comment on lines 118 to 124
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. */
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Comment on lines 143 to 146
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. */
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Comment on lines 14 to 26
@@ -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 = '';
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Comment on lines +48 to +53
protected override _datePartDeltas: DatePartDeltas = {
date: 1,
month: 1,
year: 1,
};

Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_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.

Suggested change
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;
}

Copilot uses AI. Check for mistakes.
Comment on lines +44 to +49
export interface IgcDateTimeInputComponentEventMap extends Omit<
IgcInputComponentEventMap,
'igcChange'
> {
igcChange: CustomEvent<Date | DateRangeValue | null>;
}
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Comment on lines +258 to +262
* Emits the input event after user interaction.
*/
protected _emitInputEvent(): void {
this._setTouchedState();
this.emitEvent('igcInput', { detail: this.value?.toString() });
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_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.

Suggested change
* 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() });

Copilot uses AI. Check for mistakes.
interface IgcInputArgs {
/** The value of the control. */
value: string | Date;
value: string | Date | DateRangeValue;
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
value: string | Date | DateRangeValue;
value: string;

Copilot uses AI. Check for mistakes.
* Regardless of the currently set `value-mode`, an empty value will return an empty string.
*/
value: string | Date;
value: string | Date | DateRangeValue;
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
value: string | Date | DateRangeValue;
value: string;

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Editable date range input

4 participants