chore: refactoring and cleanup

This commit is contained in:
ben-basten
2024-09-18 23:22:18 -04:00
parent 8c74d89420
commit fdd0729c4a
2 changed files with 27 additions and 31 deletions
@@ -53,20 +53,17 @@
let optionRefs: HTMLElement[] = []; let optionRefs: HTMLElement[] = [];
let input: HTMLInputElement; let input: HTMLInputElement;
let bounds: DOMRect | undefined; let bounds: DOMRect | undefined;
let scrollable: Element | null; let scrollableAncestor: Element | null;
let direction: 'bottom' | 'top' = 'bottom'; let dropdownDirection: 'bottom' | 'top' = 'bottom';
const inputId = `combobox-${id}`; const inputId = `combobox-${id}`;
const listboxId = `listbox-${id}`; const listboxId = `listbox-${id}`;
const dropdownOffset = 15; const dropdownOffset = 15;
const observer = new IntersectionObserver( const observer = new IntersectionObserver(
(entries) => { (entries) => {
if (!isOpen) { const inputEntry = entries[0];
return; if (inputEntry.intersectionRatio < 1) {
} isOpen = false;
for (const entry of entries) {
if (entry.intersectionRatio < 1) {
isOpen = false;
}
} }
}, },
{ threshold: 0.5 }, { threshold: 0.5 },
@@ -80,20 +77,14 @@
$: position = calculatePosition(bounds); $: position = calculatePosition(bounds);
$: {
if (input) {
scrollable?.removeEventListener('scroll', onPositionChange);
scrollable = input.closest('.overflow-y-auto, .overflow-y-scroll');
scrollable?.addEventListener('scroll', onPositionChange);
}
}
onMount(() => { onMount(() => {
observer.observe(input); observer.observe(input);
scrollableAncestor = input.closest('.overflow-y-auto, .overflow-y-scroll');
scrollableAncestor?.addEventListener('scroll', onPositionChange);
}); });
onDestroy(() => { onDestroy(() => {
scrollable?.removeEventListener('scroll', onPositionChange); scrollableAncestor?.removeEventListener('scroll', onPositionChange);
observer.disconnect(); observer.disconnect();
}); });
@@ -158,7 +149,7 @@
}; };
const calculatePosition = (boundary: DOMRect | undefined) => { const calculatePosition = (boundary: DOMRect | undefined) => {
direction = getComboboxDirection(boundary); dropdownDirection = getComboboxDirection(boundary);
if (!boundary) { if (!boundary) {
return undefined; return undefined;
@@ -166,12 +157,12 @@
const viewportHeight = window.innerHeight; const viewportHeight = window.innerHeight;
if (direction === 'top') { if (dropdownDirection === 'top') {
return { return {
bottom: `${viewportHeight - boundary.top}px`, bottom: `${viewportHeight - boundary.top}px`,
left: `${boundary.left}px`, left: `${boundary.left}px`,
width: `${boundary.width}px`, width: `${boundary.width}px`,
maxHeight: `${boundary.top - dropdownOffset}px`, maxHeight: maxHeight(boundary.top - dropdownOffset),
}; };
} }
@@ -180,10 +171,14 @@
top: `${boundary.bottom}px`, top: `${boundary.bottom}px`,
left: `${boundary.left}px`, left: `${boundary.left}px`,
width: `${boundary.width}px`, width: `${boundary.width}px`,
maxHeight: `${availableHeight - dropdownOffset}px`, maxHeight: maxHeight(availableHeight - dropdownOffset),
}; };
}; };
const maxHeight = (size: number) => {
return `min(${size}px,18rem)`;
};
const onPositionChange = () => { const onPositionChange = () => {
if (!isOpen) { if (!isOpen) {
return; return;
@@ -197,9 +192,10 @@
} }
const viewportHeight = window.innerHeight; const viewportHeight = window.innerHeight;
const availableHeight = viewportHeight - boundary.bottom; const heightBelow = viewportHeight - boundary.bottom;
const heightAbove = boundary.top;
return availableHeight > 150 ? 'bottom' : 'top'; return heightBelow <= 225 && heightAbove > heightBelow ? 'top' : 'bottom';
}; };
const getInputPosition = () => input?.getBoundingClientRect(); const getInputPosition = () => input?.getBoundingClientRect();
@@ -238,8 +234,8 @@
autocomplete="off" autocomplete="off"
bind:this={input} bind:this={input}
class:!pl-8={isActive} class:!pl-8={isActive}
class:!rounded-b-none={isOpen && direction === 'bottom'} class:!rounded-b-none={isOpen && dropdownDirection === 'bottom'}
class:!rounded-t-none={isOpen && direction === 'top'} class:!rounded-t-none={isOpen && dropdownDirection === 'top'}
class:cursor-pointer={!isActive} class:cursor-pointer={!isActive}
class="immich-form-input text-sm text-left w-full !pr-12 transition-all" class="immich-form-input text-sm text-left w-full !pr-12 transition-all"
id={inputId} id={inputId}
@@ -307,15 +303,15 @@
id={listboxId} id={listboxId}
transition:fly={{ duration: 250 }} transition:fly={{ duration: 250 }}
class="fixed text-left text-sm w-full overflow-y-auto bg-white dark:bg-gray-800 border-gray-300 dark:border-gray-900 z-[10000]" class="fixed text-left text-sm w-full overflow-y-auto bg-white dark:bg-gray-800 border-gray-300 dark:border-gray-900 z-[10000]"
class:rounded-b-xl={direction === 'bottom'} class:rounded-b-xl={dropdownDirection === 'bottom'}
class:rounded-t-xl={direction === 'top'} class:rounded-t-xl={dropdownDirection === 'top'}
class:shadow={direction === 'bottom'} class:shadow={dropdownDirection === 'bottom'}
class:border={isOpen} class:border={isOpen}
style:top={position?.top} style:top={position?.top}
style:bottom={position?.bottom} style:bottom={position?.bottom}
style:left={position?.left} style:left={position?.left}
style:width={position?.width} style:width={position?.width}
style:max-height="min({position?.maxHeight},18rem)" style:max-height={position?.maxHeight}
tabindex="-1" tabindex="-1"
> >
{#if isOpen} {#if isOpen}
@@ -74,7 +74,7 @@
aria-modal="true" aria-modal="true"
aria-labelledby={titleId} aria-labelledby={titleId}
> >
<div class="immich-scrollbar overflow-y-auto py-1"> <div class="immich-scrollbar overflow-y-auto pt-1" class:pb-4={isStickyBottom}>
<ModalHeader id={titleId} {title} {showLogo} {icon} {onClose} /> <ModalHeader id={titleId} {title} {showLogo} {icon} {onClose} />
<div class="px-5 pt-0"> <div class="px-5 pt-0">
<slot /> <slot />