Skip to content

Commit 261820e

Browse files
committed
fix(material/datepicker): date range inputs not aligning in some cases (#25967)
Currently we use two different approaches to align the start and end parts of the date range. The start is absolutely-positioned while the end is `relative` which ends up misaligning on some browsers and typography configurations. These changes make both positioned absolutely since some browsers don't handle `line-height` on inputs reliably. Fixes #25955. (cherry picked from commit 7d268b5)
1 parent e1686a8 commit 261820e

File tree

5 files changed

+38
-34
lines changed

5 files changed

+38
-34
lines changed

src/material/datepicker/date-range-input-parts.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,13 @@ abstract class MatDateRangeInputPartBase<D>
142142
this._elementRef.nativeElement.focus();
143143
}
144144

145+
/** Gets the value that should be used when mirroring the input's size. */
146+
getMirrorValue(): string {
147+
const element = this._elementRef.nativeElement;
148+
const value = element.value;
149+
return value.length > 0 ? value : element.placeholder;
150+
}
151+
145152
/** Handles `input` events on the input element. */
146153
override _onInput(value: string) {
147154
super._onInput(value);
@@ -286,13 +293,6 @@ export class MatStartDate<D> extends _MatDateRangeInputBase<D> implements CanUpd
286293
this._rangeInput._handleChildValueChange();
287294
}
288295

289-
/** Gets the value that should be used when mirroring the input's size. */
290-
getMirrorValue(): string {
291-
const element = this._elementRef.nativeElement;
292-
const value = element.value;
293-
return value.length > 0 ? value : element.placeholder;
294-
}
295-
296296
override _onKeydown(event: KeyboardEvent) {
297297
const endInput = this._rangeInput._endInput;
298298
const element = this._elementRef.nativeElement;

src/material/datepicker/date-range-input.html

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,22 @@
22
class="mat-date-range-input-container"
33
cdkMonitorSubtreeFocus
44
(cdkFocusChange)="_updateFocus($event)">
5-
<div class="mat-date-range-input-start-wrapper">
5+
<div class="mat-date-range-input-wrapper">
66
<ng-content select="input[matStartDate]"></ng-content>
77
<span
88
class="mat-date-range-input-mirror"
9-
aria-hidden="true">{{_getInputMirrorValue()}}</span>
9+
aria-hidden="true">{{_getInputMirrorValue('start')}}</span>
1010
</div>
1111

1212
<span
1313
class="mat-date-range-input-separator"
1414
[class.mat-date-range-input-separator-hidden]="_shouldHideSeparator()">{{separator}}</span>
1515

16-
<div class="mat-date-range-input-end-wrapper">
16+
<div class="mat-date-range-input-wrapper mat-date-range-input-end-wrapper">
1717
<ng-content select="input[matEndDate]"></ng-content>
18+
<span
19+
class="mat-date-range-input-mirror"
20+
aria-hidden="true">{{_getInputMirrorValue('end')}}</span>
1821
</div>
1922
</div>
2023

src/material/datepicker/date-range-input.scss

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,24 @@ $date-range-input-part-max-width: calc(50% - #{$date-range-input-separator-spaci
4545
transition: none;
4646
}
4747

48+
// Wrapper around the inner inputs. Used to facilitate the auto-resizing input.
49+
.mat-date-range-input-wrapper {
50+
position: relative;
51+
overflow: hidden;
52+
max-width: $date-range-input-part-max-width;
53+
}
54+
55+
.mat-date-range-input-end-wrapper {
56+
// Allow the end input to fill the rest of the available space.
57+
flex-grow: 1;
58+
}
59+
4860
// Underlying input inside the range input.
4961
.mat-date-range-input-inner {
62+
position: absolute;
63+
top: 0;
64+
left: 0;
65+
5066
// Reset the input so it's just a transparent rectangle.
5167
font: inherit;
5268
background: transparent;
@@ -60,6 +76,10 @@ $date-range-input-part-max-width: calc(50% - #{$date-range-input-separator-spaci
6076
-webkit-appearance: none;
6177
width: 100%;
6278

79+
// Does nothing on Chrome, but necessary for the text
80+
// to align in some cases on Safari and Firefox.
81+
height: 100%;
82+
6383
// Undo the red box-shadow glow added by Firefox on invalid inputs.
6484
// See https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-ui-invalid
6585
&:-moz-ui-invalid {
@@ -101,7 +121,7 @@ $date-range-input-part-max-width: calc(50% - #{$date-range-input-separator-spaci
101121
// We want the start input to be flush against the separator, no matter how much text it has, but
102122
// the problem is that inputs have a fixed width. We work around the issue by implementing an
103123
// auto-resizing input that stretches based on its text, up to a point. It works by having
104-
// a relatively-positioned wrapper (`.mat-date-range-input-start-wrapper` below) and an absolutely-
124+
// a relatively-positioned wrapper (`.mat-date-range-input-wrapper` below) and an absolutely-
105125
// positioned `input`, as well as a `span` inside the wrapper which mirrors the input's value and
106126
// placeholder. As the user is typing, the value gets mirrored in the span which causes the wrapper
107127
// to stretch and the input with it.
@@ -122,25 +142,6 @@ $date-range-input-part-max-width: calc(50% - #{$date-range-input-separator-spaci
122142
min-width: 2px;
123143
}
124144

125-
// Wrapper around the start input. Used to facilitate the auto-resizing input.
126-
.mat-date-range-input-start-wrapper {
127-
position: relative;
128-
overflow: hidden;
129-
max-width: $date-range-input-part-max-width;
130-
131-
.mat-date-range-input-inner {
132-
position: absolute;
133-
top: 0;
134-
left: 0;
135-
}
136-
}
137-
138-
// Wrapper around the end input that makes sure that it has the proper size.
139-
.mat-date-range-input-end-wrapper {
140-
flex-grow: 1;
141-
max-width: $date-range-input-part-max-width;
142-
}
143-
144145
.mat-mdc-form-field-type-mat-date-range-input .mat-mdc-form-field-infix {
145146
// Bump the default width slightly since it's somewhat cramped with two inputs and a separator.
146147
width: 200px;

src/material/datepicker/date-range-input.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -349,8 +349,9 @@ export class MatDateRangeInput<D>
349349
}
350350

351351
/** Gets the value that is used to mirror the state input. */
352-
_getInputMirrorValue() {
353-
return this._startInput ? this._startInput.getMirrorValue() : '';
352+
_getInputMirrorValue(part: 'start' | 'end') {
353+
const input = part === 'start' ? this._startInput : this._endInput;
354+
return input ? input.getMirrorValue() : '';
354355
}
355356

356357
/** Whether the input placeholders should be hidden. */

tools/public_api_guard/material/datepicker.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -575,7 +575,7 @@ export class MatDateRangeInput<D> implements MatFormFieldControl<DateRange<D>>,
575575
getConnectedOverlayOrigin(): ElementRef;
576576
// (undocumented)
577577
_getEndDateAccessibleName(): string;
578-
_getInputMirrorValue(): string;
578+
_getInputMirrorValue(part: 'start' | 'end'): string;
579579
getOverlayLabelId(): string | null;
580580
// (undocumented)
581581
_getStartDateAccessibleName(): string;
@@ -811,7 +811,6 @@ export class MatStartDate<D> extends _MatDateRangeInputBase<D> implements CanUpd
811811
protected _assignValueToModel(value: D | null): void;
812812
// (undocumented)
813813
protected _formatValue(value: D | null): void;
814-
getMirrorValue(): string;
815814
// (undocumented)
816815
protected _getValueFromModel(modelValue: DateRange<D>): D | null;
817816
// (undocumented)

0 commit comments

Comments
 (0)