UNPKG

outsystems-ui

Version:
131 lines (121 loc) 5.08 kB
// eslint-disable-next-line @typescript-eslint/no-unused-vars namespace Providers.OSUI.SharedProviderResources.Flatpickr { export class UpdatePositionOnScroll { // Indicates wether the picker is a time picker or other type of picker (Month, Date, DateTime). private _isTimePicker: boolean; // Event OnScreenScroll private _onScrollEvent: OSFramework.OSUI.GlobalCallbacks.Generic; // Store the parent Sidebar instance if any private _parentSidebar: HTMLElement; // Store the picker instance private _picker: | Datepicker.Flatpickr.IFlatpickr | TimePicker.Flatpickr.IFlatpickrTime | MonthPicker.Flatpickr.IFlatpickrMonth; // Store the RequestAnimationFrame that will be triggered at OnBodyScroll private _requestAnimationOnBodyScroll: number; constructor( picker: | Datepicker.Flatpickr.IFlatpickr | TimePicker.Flatpickr.IFlatpickrTime | MonthPicker.Flatpickr.IFlatpickrMonth ) { // Set picker object this._picker = picker; // Set if the picker is a time picker this._isTimePicker = this._picker instanceof TimePicker.Flatpickr.OSUIFlatpickrTime; // Set parent Sidebar this._parentSidebar = picker.selfElement.closest( `${OSFramework.OSUI.Constants.Dot}${OSFramework.OSUI.Patterns.Sidebar.Enum.CssClass.Content}` ); // Set onBodyScrollEvent callback this._setCallbacks(); // Set the Events this._setUpEvents(); } // Update the calendar position private _onScreenScroll(): void { if (this._picker.isBuilt) { // Check if IsPhone if (this._picker.provider.isOpen && OSFramework.OSUI.Helper.DeviceInfo.IsPhone) { /** * This condition checks if the active element is not a child of the calendar container. * This is necessary due to the design of active-screen and content containers in both web * and native mobile app environments, where `overflow-y` is set to `auto`. This setting * allows content to be scrollable even when a picker is open in native apps, which could * lead to unintended scrolling of the entire screen, including the header, when interacting * with the picker. To prevent this, the calendar's position is updated to remain in view * during scroll events. * * However, this behavior is excluded for the timepicker. When the timepicker is triggered * (e.g., by focusing on an input field), the appearance of the keyboard may cause the page * to scroll. In this scenario, we avoid closing the timepicker to maintain user interaction * continuity. */ if ( this._isTimePicker || document.activeElement.closest( `${OSFramework.OSUI.Constants.Dot}${Enum.CssClasses.CalendarContainer}` ) === this._picker.provider.calendarContainer ) { // Prevents the calendar from closing and updates its position to stay in view. this._picker.provider._positionCalendar(); } else { // Closes the calendar if the active element is outside the calendar container. this._picker.provider.close(); } } // Ensure app is not running as a phone if (OSFramework.OSUI.Helper.DeviceInfo.IsPhone === false) { // Since it's at desktop or tablet, update it's position if it's open! if (this._picker.provider.isOpen) { // trigger provider update position method this._picker.provider._positionCalendar(); // Update the "position" before the next "repaint" this._requestAnimationOnBodyScroll = requestAnimationFrame(this._onScrollEvent); } else if (this._requestAnimationOnBodyScroll !== undefined) { cancelAnimationFrame(this._requestAnimationOnBodyScroll); } } } } // Method used to set callbacks private _setCallbacks(): void { this._onScrollEvent = this._onScreenScroll.bind(this); } // Add Events private _setUpEvents(): void { // Add the BodyScroll callback that will be used to update the balloon coordinates OSFramework.OSUI.Event.DOMEvents.Listeners.GlobalListenerManager.Instance.addHandler( OSFramework.OSUI.Event.DOMEvents.Listeners.Type.ScreenOnScroll, this._onScrollEvent ); // If the picker is inside a Sidebar, let's add the method to the Sidebar content as well. if (this._parentSidebar) { this._parentSidebar.addEventListener(OSFramework.OSUI.GlobalEnum.HTMLEvent.Scroll, this._onScrollEvent); } } // Method used to unset callbacks private _unsetCallbacks(): void { this._onScrollEvent = undefined; } // Remove Added Events private _unsetEvents(): void { OSFramework.OSUI.Event.DOMEvents.Listeners.GlobalListenerManager.Instance.removeHandler( OSFramework.OSUI.Event.DOMEvents.Listeners.Type.ScreenOnScroll, this._onScrollEvent ); } /** * Method to remove and destroy instance events and properties! * * @memberof Providers.OSUI.SharedProviderResources.Flatpickr.UpdatePositionOnScroll */ public dispose(): void { this._unsetEvents(); this._unsetCallbacks(); this._onScrollEvent = undefined; this._requestAnimationOnBodyScroll = undefined; } } }