improved dropdown on mobile

This commit is contained in:
Jakob Pinterits
2024-07-25 23:59:19 +02:00
parent 484f36397a
commit 710577acb7
3 changed files with 57 additions and 29 deletions

View File

@@ -109,18 +109,37 @@ export class DropdownComponent extends ComponentBase {
// Position & Animate
let anchorRect = this.element.getBoundingClientRect();
let popupHeight = this.popupElement.scrollHeight;
let windowWidth = window.innerWidth - 1; // innerWidth is rounded
let windowHeight = window.innerHeight - 1; // innerHeight is rounded
const WINDOW_MARGIN = 0.5 * pixelsPerRem;
const DESKTOP_WINDOW_MARGIN = 0.5 * pixelsPerRem;
const MOBILE_WINDOW_MARGIN = 2 * pixelsPerRem;
const GAP_IF_ENTIRELY_ABOVE = 0.5 * pixelsPerRem;
// On small screens, such as phones, go fullscreen
if (false) {
//
// TODO: Adjust these thresholds. Maybe have a global variable which
// keeps track of whether we're on mobile?
console.debug(
`Width: ${windowWidth / pixelsPerRem}rem Height: ${
windowHeight / pixelsPerRem
}rem`
);
if (
windowWidth < 60 * pixelsPerRem ||
windowHeight < 40 * pixelsPerRem
) {
// Make sure mobile browsers don't display a keyboard
this.inputBox.inputElement.readOnly = true;
// Style the popup
this.popupElement.classList.add('rio-dropdown-popup-fullscreen');
if (popupHeight >= windowHeight - 2 * WINDOW_MARGIN) {
if (popupHeight >= windowHeight - 2 * MOBILE_WINDOW_MARGIN) {
return {
'max-height': `${windowHeight - 2 * WINDOW_MARGIN}px`,
'max-height': `${
windowHeight - 2 * MOBILE_WINDOW_MARGIN
}px`,
'overflow-y': 'scroll',
};
} else {
@@ -131,23 +150,27 @@ export class DropdownComponent extends ComponentBase {
}
}
this.inputBox.inputElement.readOnly = false;
this.popupElement.classList.remove('rio-dropdown-popup-fullscreen');
// Popup is larger than the window. Give it all the space that's
// available.
if (popupHeight >= windowHeight - 2 * WINDOW_MARGIN) {
if (popupHeight >= windowHeight - 2 * DESKTOP_WINDOW_MARGIN) {
return {
left: `${anchorRect.left}px`,
top: `${WINDOW_MARGIN}px`,
top: `${DESKTOP_WINDOW_MARGIN}px`,
width: `${anchorRect.width}px`,
'max-height': `${windowHeight - 2 * WINDOW_MARGIN}px`,
'max-height': `${windowHeight - 2 * DESKTOP_WINDOW_MARGIN}px`,
'overflow-y': 'scroll',
'border-radius': 'var(--rio-global-corner-radius-small)',
};
}
// Popup fits below the dropdown
if (anchorRect.bottom + popupHeight + WINDOW_MARGIN <= windowHeight) {
if (
anchorRect.bottom + popupHeight + DESKTOP_WINDOW_MARGIN <=
windowHeight
) {
return {
left: `${anchorRect.left}px`,
top: `${anchorRect.bottom}px`,
@@ -159,7 +182,7 @@ export class DropdownComponent extends ComponentBase {
// Popup fits above the dropdown
else if (
anchorRect.top - popupHeight >=
GAP_IF_ENTIRELY_ABOVE + WINDOW_MARGIN
GAP_IF_ENTIRELY_ABOVE + DESKTOP_WINDOW_MARGIN
) {
return {
left: `${anchorRect.left}px`,
@@ -177,10 +200,13 @@ export class DropdownComponent extends ComponentBase {
else {
console.debug('TRIG');
let top = anchorRect.top + anchorRect.height / 2 - popupHeight / 2;
if (top < WINDOW_MARGIN) {
top = WINDOW_MARGIN;
} else if (top + popupHeight + WINDOW_MARGIN > windowHeight) {
top = windowHeight - popupHeight - WINDOW_MARGIN;
if (top < DESKTOP_WINDOW_MARGIN) {
top = DESKTOP_WINDOW_MARGIN;
} else if (
top + popupHeight + DESKTOP_WINDOW_MARGIN >
windowHeight
) {
top = windowHeight - popupHeight - DESKTOP_WINDOW_MARGIN;
}
return {

View File

@@ -63,12 +63,13 @@ export class FundamentalRootComponent extends ComponentBase {
'.rio-dev-tools-container'
) as HTMLElement;
// Notify the backend whenever the "window" size changes (it's not
// really the whole window because the dev tools sidebar is excluded)
// Watch for "window" size changes (it's not really the whole window
// because the dev tools sidebar is excluded)
let outerUserRootContainer = element.querySelector(
'.rio-user-root-container-outer'
) as HTMLElement;
new ResizeObserver(() => {
// Notify the backend of the new size
let rect = outerUserRootContainer.getBoundingClientRect();
notifyBackendOfWindowSizeChange.call(
rect.width / pixelsPerRem,

View File

@@ -956,7 +956,9 @@ $rio-input-box-small-label-spacing-top: 0.5rem;
}
.rio-dropdown-popup {
transition: max-height 0.2s ease-in-out;
transition:
max-height 0.2s ease-in-out,
box-shadow 0.2s ease-in-out;
}
.rio-dropdown-popup:not(.rio-popup-manager-open) {
@@ -964,26 +966,25 @@ $rio-input-box-small-label-spacing-top: 0.5rem;
}
.rio-dropdown-popup-fullscreen {
position: absolute;
z-index: $z-index-popup;
left: 50%;
top: 50%;
min-width: 12rem;
min-width: 15rem;
transform: translate(-50%, -50%);
background-color: var(--rio-global-neutral-bg);
border-radius: var(--rio-global-corner-radius-medium);
// FIXME: This should really shade the entire screen rather than just be a
// shadow. However, after spending hours on trying - and failing - to get
// this to work, I've decided a shadow will do.
box-shadow: 0 0 0 transparent;
}
.rio-dropdown-popup-fullscreen::before {
content: '';
pointer-events: none;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
// background-color: rgba(0, 0, 0, 0.5);
z-index: $z-index-popup - 1;
.rio-dropdown-popup-fullscreen.rio-popup-manager-open {
box-shadow: 0 0 3rem var(--rio-global-shadow-color);
}
.rio-dropdown-arrow {