Skip to content

Commit c6e594b

Browse files
committed
feat(datetime-button): ensure overlays are sized correctly
1 parent 98879f0 commit c6e594b

File tree

1 file changed

+94
-1
lines changed

1 file changed

+94
-1
lines changed

core/src/components/datetime-button/datetime-button.tsx

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { getIonMode } from '../../global/ionic-global';
55
import type { Color, DatetimePresentation } from '../../interface';
66
import { createColorClasses } from '../../utils/theme';
77
import { printIonError } from '../../utils/logging';
8-
import { componentOnReady, addEventListener } from '../../utils/helpers';
8+
import { componentOnReady, addEventListener, raf } from '../../utils/helpers';
99
import { parseDate } from '../datetime/utils/parse';
1010
import { getToday } from '../datetime/utils/data';
1111
import { is24Hour } from '../datetime/utils/helpers';
@@ -20,6 +20,7 @@ import { getMonthAndYear, getMonthDayAndYear, getLocalizedDateTime, getLocalized
2020
})
2121
export class DatetimeButton implements ComponentInterface {
2222
private datetimeEl: HTMLIonDatetimeElement | null = null;
23+
private overlayEl: HTMLElement | null = null;
2324

2425
// STUBS
2526
@State() datetimePresentation?: DatetimePresentation = 'date-time';
@@ -80,7 +81,22 @@ export class DatetimeButton implements ComponentInterface {
8081

8182
io.observe(datetimeEl);
8283

84+
/**
85+
* Get a reference to any modal/popover
86+
* the datetime is being used in so we can
87+
* correctly size it when it is presented.
88+
*/
89+
const overlayEl = this.overlayEl = datetimeEl.closest('ion-modal, ion-popover');
90+
8391
componentOnReady(datetimeEl, () => {
92+
/**
93+
* Datetimes in overlays linked with datetime-button
94+
* should display full width so that the overlay
95+
* can be sized correctly.
96+
*/
97+
if (overlayEl) {
98+
datetimeEl.size = 'cover';
99+
}
84100
const datetimePresentation = (this.datetimePresentation = datetimeEl.presentation || 'date-time');
85101

86102
/**
@@ -201,6 +217,8 @@ export class DatetimeButton implements ComponentInterface {
201217
* the datetime is opened.
202218
*/
203219
this.selectedButton = 'date';
220+
221+
this.setOverlaySize();
204222
};
205223

206224
private handleTimeClick = () => {
@@ -234,8 +252,83 @@ export class DatetimeButton implements ComponentInterface {
234252
* the datetime is opened.
235253
*/
236254
this.selectedButton = 'time';
255+
256+
this.setOverlaySize();
237257
};
238258

259+
/**
260+
* If the datetime is presented in an
261+
* overlay, the datetime and overlay
262+
* should be appropriately size.
263+
* These classes provide default sizing values
264+
* that developers can customize.
265+
* The goal is to provide an overlay that
266+
* reasonably sized with a datetime that
267+
* fills the entire container.
268+
*/
269+
private setOverlaySize = () => {
270+
const { overlayEl, datetimeEl } = this;
271+
272+
if (!overlayEl || !datetimeEl) {
273+
return;
274+
}
275+
276+
const { presentation } = datetimeEl;
277+
278+
/**
279+
* All datetime overlays should have
280+
* a consistent width and border radius.
281+
* This is controlled by the ion-datetime-button-overlay
282+
* class which developers can customize globally.
283+
*/
284+
overlayEl.classList.add('ion-datetime-button-overlay');
285+
286+
/**
287+
* Wheel picker styles in datetime always
288+
* have a fixed height of 200px. This is
289+
* because the buttons/headers are not shown
290+
* with the wheel picker by design.
291+
*/
292+
const hasWheelPicker = ['month', 'year', 'month-year', 'time'].includes(presentation);
293+
const needsWiderWheel = presentation === 'month-year';
294+
295+
if (hasWheelPicker) {
296+
overlayEl.style.setProperty('--height', `200px`);
297+
298+
/**
299+
* The default width for month-year
300+
* is too small, so we set it to 300px so
301+
* the text is not cut off.
302+
*/
303+
if (needsWiderWheel) {
304+
overlayEl.style.setProperty('--width', '300px');
305+
}
306+
307+
/**
308+
* If we are not using the
309+
* wheel picker then we need to automatically
310+
* determine the height of the datetime by
311+
* looking at scrollHeight. We look at scrollHeight
312+
* as it will give us the height of the datetime
313+
* even if it overflows outside of the overlay initially.
314+
*
315+
* We also wait a frame to allow the browser to
316+
* unhide the overlay and calculate the size
317+
* of the datetime.
318+
*
319+
* Doing this means developers can control the size
320+
* of the overlay by setting the height of
321+
* the datetime directly.
322+
*/
323+
} else {
324+
overlayEl.style.setProperty('--width', '300px');
325+
326+
raf(() => {
327+
overlayEl.style.setProperty('--height', `${datetimeEl.scrollHeight}px`);
328+
});
329+
}
330+
}
331+
239332
render() {
240333
const { color, dateText, timeText, datetimePresentation, selectedButton, datetimeActive } = this;
241334

0 commit comments

Comments
 (0)