feat: zooming and virtual keyboard working for iPadOS/Safari

This commit is contained in:
ben-basten 2024-09-19 23:22:05 -04:00
parent fdd0729c4a
commit cac29bac0d
No known key found for this signature in database
GPG Key ID: 78803E894B258348

View File

@ -21,7 +21,7 @@
import { fly } from 'svelte/transition';
import Icon from '$lib/components/elements/icon.svelte';
import { mdiMagnify, mdiUnfoldMoreHorizontal, mdiClose } from '@mdi/js';
import { createEventDispatcher, onDestroy, onMount, tick } from 'svelte';
import { createEventDispatcher, onMount, tick } from 'svelte';
import type { FormEventHandler } from 'svelte/elements';
import { shortcuts } from '$lib/actions/shortcut';
import { focusOutside } from '$lib/actions/focus-outside';
@ -52,6 +52,7 @@
let selectedIndex: number | undefined;
let optionRefs: HTMLElement[] = [];
let input: HTMLInputElement;
let dropdown: HTMLUListElement;
let bounds: DOMRect | undefined;
let scrollableAncestor: Element | null;
let dropdownDirection: 'bottom' | 'top' = 'bottom';
@ -81,11 +82,15 @@
observer.observe(input);
scrollableAncestor = input.closest('.overflow-y-auto, .overflow-y-scroll');
scrollableAncestor?.addEventListener('scroll', onPositionChange);
});
window.visualViewport?.addEventListener('resize', onPositionChange);
window.visualViewport?.addEventListener('scroll', onPositionChange);
onDestroy(() => {
scrollableAncestor?.removeEventListener('scroll', onPositionChange);
observer.disconnect();
return () => {
observer.disconnect();
scrollableAncestor?.removeEventListener('scroll', onPositionChange);
window.visualViewport?.removeEventListener('resize', onPositionChange);
window.visualViewport?.removeEventListener('scroll', onPositionChange);
};
});
const dispatch = createEventDispatcher<{
@ -155,21 +160,28 @@
return undefined;
}
const viewportHeight = window.innerHeight;
const vv = window.visualViewport;
const viewportHeight = vv?.height || 0;
const left = boundary.left + (vv?.offsetLeft || 0);
const offsetTop = vv?.offsetTop || 0;
if (dropdownDirection === 'top') {
const dropdownHeight = dropdown?.clientHeight || 0;
const availableHeight = boundary.top - dropdownOffset;
const adjustTop = Math.max(availableHeight - dropdownHeight, 0);
return {
bottom: `${viewportHeight - boundary.top}px`,
left: `${boundary.left}px`,
top: `${dropdownOffset + offsetTop + adjustTop}px`,
left: `${left}px`,
width: `${boundary.width}px`,
maxHeight: maxHeight(boundary.top - dropdownOffset),
maxHeight: maxHeight(availableHeight),
};
}
const top = boundary.bottom + offsetTop;
const availableHeight = viewportHeight - boundary.bottom;
return {
top: `${boundary.bottom}px`,
left: `${boundary.left}px`,
top: `${top}px`,
left: `${left}px`,
width: `${boundary.width}px`,
maxHeight: maxHeight(availableHeight - dropdownOffset),
};
@ -191,7 +203,7 @@
return 'bottom';
}
const viewportHeight = window.innerHeight;
const viewportHeight = window.visualViewport?.height || 0;
const heightBelow = viewportHeight - boundary.bottom;
const heightAbove = boundary.top;
@ -201,7 +213,6 @@
const getInputPosition = () => input?.getBoundingClientRect();
</script>
<svelte:window on:resize={onPositionChange} />
<label class="immich-form-label" class:sr-only={hideLabel} for={inputId}>{label}</label>
<div
class="relative w-full dark:text-gray-300 text-gray-700 text-base"
@ -308,11 +319,11 @@
class:shadow={dropdownDirection === 'bottom'}
class:border={isOpen}
style:top={position?.top}
style:bottom={position?.bottom}
style:left={position?.left}
style:width={position?.width}
style:max-height={position?.maxHeight}
tabindex="-1"
bind:this={dropdown}
>
{#if isOpen}
{#if filteredOptions.length === 0}