chore: refactoring and cleanup
This commit is contained in:
@@ -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 />
|
||||||
|
|||||||
Reference in New Issue
Block a user