Skip to content

Commit ba91353

Browse files
authored
fix(core/time-input): Invalid input of time-input breaks the component (#2024)
1 parent e44cb49 commit ba91353

File tree

5 files changed

+98
-2
lines changed

5 files changed

+98
-2
lines changed

packages/core/src/components/date-input/date-input.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ export class DateInput implements IxInputFieldComponent<string | undefined> {
7070
*/
7171
@Prop({ reflect: true, mutable: true }) value?: string = '';
7272

73+
@Watch('value') watchValuePropHandler(newValue: string) {
74+
this.onInput(newValue);
75+
}
76+
7377
/**
7478
* The earliest date that can be selected by the date input/picker.
7579
* If not set there will be no restriction.

packages/core/src/components/date-input/tests/date-input.ct.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,3 +179,25 @@ regressionTest(
179179
expect(formData).toBe('2024/12/12');
180180
}
181181
);
182+
183+
regressionTest(
184+
'updating component value attribute updates validity',
185+
async ({ page, mount }) => {
186+
await mount(`<ix-date-input value="2024/05/05"></ix-date-input>`);
187+
188+
const dateInput = page.locator('ix-date-input');
189+
const input = page.locator('input');
190+
191+
await dateInput.evaluateHandle((el) => {
192+
el.setAttribute('value', 'invalid-date');
193+
});
194+
195+
await expect(input).toHaveClass(/is-invalid/);
196+
197+
await dateInput.evaluateHandle((el) => {
198+
el.setAttribute('value', '2024/05/05');
199+
});
200+
201+
await expect(input).not.toHaveClass(/is-invalid/);
202+
}
203+
);

packages/core/src/components/time-input/test/time-input.ct.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,4 +100,67 @@ regressionTest.describe('time input tests', () => {
100100
await expect(page.locator('input')).toHaveValue('12:30:45');
101101
}
102102
);
103+
104+
regressionTest(
105+
'closing dropdown and reopening after entering invalid time does not break component',
106+
async ({ page }) => {
107+
const input = page.locator('input');
108+
const fieldWrapper = page.locator('ix-field-wrapper');
109+
const dropdown = page.locator('ix-dropdown[data-testid="time-dropdown"]');
110+
const iconButton = page.locator(
111+
'ix-icon-button[data-testid="open-time-picker"]'
112+
);
113+
114+
await input.click();
115+
116+
await expect(dropdown).toHaveClass(/show/);
117+
118+
await expect(page.locator('ix-time-picker')).toBeVisible();
119+
120+
await input.fill('invalid-time');
121+
122+
await expect(input).toHaveClass(/is-invalid/);
123+
await expect(fieldWrapper).toContainText('Time is not valid');
124+
125+
await iconButton.click();
126+
127+
await expect(dropdown).not.toHaveClass(/show/);
128+
129+
await expect(input).toHaveClass(/is-invalid/);
130+
await expect(fieldWrapper).toContainText('Time is not valid');
131+
132+
await iconButton.click();
133+
134+
await expect(dropdown).toHaveClass(/show/);
135+
136+
await page
137+
.locator('ix-time-picker [data-element-container-id="second-30"]')
138+
.click();
139+
140+
await page.locator('ix-time-picker ix-button').click();
141+
142+
await expect(input).not.toHaveClass(/is-invalid/);
143+
await expect(fieldWrapper).not.toContainText('Time is not valid');
144+
}
145+
);
146+
147+
regressionTest(
148+
'updating component value attribute updates validity',
149+
async ({ page }) => {
150+
const timeInput = page.locator('ix-time-input');
151+
const input = page.locator('input');
152+
153+
await timeInput.evaluateHandle((el) => {
154+
el.setAttribute('value', 'invalid-time');
155+
});
156+
157+
await expect(input).toHaveClass(/is-invalid/);
158+
159+
await timeInput.evaluateHandle((el) => {
160+
el.setAttribute('value', '09:10:11');
161+
});
162+
163+
await expect(input).not.toHaveClass(/is-invalid/);
164+
}
165+
);
103166
});

packages/core/src/components/time-input/time-input.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ export class TimeInput implements IxInputFieldComponent<string> {
7171
*/
7272
@Prop({ reflect: true, mutable: true }) value: string = '';
7373

74+
@Watch('value') watchValuePropHandler(newValue: string) {
75+
this.onInput(newValue);
76+
}
77+
7478
/**
7579
* Format of time string
7680
* See {@link "https://moment.github.io/luxon/#/formatting?id=table-of-tokens"} for all available tokens.

packages/core/src/components/time-picker/time-picker.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -572,8 +572,11 @@ export class TimePicker {
572572

573573
if (!dropdown.classList.contains('show')) {
574574
// keep picker in sync with input
575-
this._time = DateTime.fromFormat(this.time, this.format);
576-
this.setInitialFocusedValueAndUnit();
575+
const timeFormat = DateTime.fromFormat(this.time, this.format);
576+
if (timeFormat.isValid) {
577+
this._time = DateTime.fromFormat(this.time, this.format);
578+
this.setInitialFocusedValueAndUnit();
579+
}
577580

578581
continue;
579582
}

0 commit comments

Comments
 (0)