feat: present cleared accessible project media
This commit is contained in:
48
src/composables/useLazyMedia.ts
Normal file
48
src/composables/useLazyMedia.ts
Normal 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,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user