feat: present cleared accessible project media

This commit is contained in:
2026-09-02 06:50:00 +03:00
parent dfd56f0a48
commit f953905a4b
12 changed files with 832 additions and 4 deletions

View File

@@ -0,0 +1,48 @@
import { computed, onMounted, onUnmounted, readonly, shallowRef, unref, type MaybeRef, type Ref } from 'vue';
export interface LazyMediaState {
nearby: Readonly<Ref<boolean>>;
shouldAttach: Readonly<Ref<boolean>>;
explicitRequested: Readonly<Ref<boolean>>;
requestExplicit(): void;
clearExplicit(): void;
}
export const MEDIA_ACTIVATION_MARGIN = '300px 0px 300px 0px';
export function useLazyMedia(
target: Readonly<Ref<Element | null>>,
allowAutomatic: MaybeRef<boolean>,
): LazyMediaState {
const nearby = shallowRef(false);
const explicitRequested = shallowRef(false);
const shouldAttach = computed(() => explicitRequested.value || (nearby.value && unref(allowAutomatic)));
let observer: IntersectionObserver | undefined;
const requestExplicit = (): void => {
explicitRequested.value = true;
};
const clearExplicit = (): void => {
explicitRequested.value = false;
};
onMounted(() => {
if (typeof IntersectionObserver !== 'function' || target.value === null) return;
observer = new IntersectionObserver((entries) => {
const inActivationRange = entries.some((entry) => entry.isIntersecting);
nearby.value = inActivationRange;
if (!inActivationRange) clearExplicit();
}, { rootMargin: MEDIA_ACTIVATION_MARGIN, threshold: 0 });
observer.observe(target.value);
});
onUnmounted(() => observer?.disconnect());
return {
nearby: readonly(nearby),
shouldAttach: readonly(shouldAttach),
explicitRequested: readonly(explicitRequested),
requestExplicit,
clearExplicit,
};
}