@empathyco/x-components
Version:
Empathy X Components
85 lines (82 loc) • 3.17 kB
JavaScript
import { defineComponent, ref, inject, onBeforeUnmount, onMounted, nextTick, watch } from 'vue';
import { useState } from '../../../composables/use-state.js';
import { useXBus } from '../../../composables/use-x-bus.js';
import { scrollXModule } from '../x-module.js';
import { ScrollObserverKey } from './scroll.const.js';
/**
* Wrapper for elements contained in the {@link MainScroll} that should store/restore its
* position.
*
* @public
*/
var _sfc_main = defineComponent({
name: 'MainScrollItem',
xModule: scrollXModule.name,
props: {
/** The item data. Used to set the scroll identifier. */
item: {
type: Object,
required: true,
},
/** The tag to render. */
tag: {
type: [String, Object],
default: 'div',
},
},
setup(props) {
const xBus = useXBus();
/** Rendered HTML node. */
const rootRef = ref();
/**
* Pending identifier scroll position to restore. If it matches the {@link MainScrollItem} item
* `id` property, this component should be scrolled into view.
*/
const { pendingScrollTo } = useState('scroll');
/** Observer to detect the first visible element. */
const firstVisibleItemObserver = inject(ScrollObserverKey, null);
/**
* Initialises the element visibility observation, stopping the previous one if it has.
*
* @param newObserver - The new observer for the HTML element.
* @param oldObserver - The old observer for the HTML element.
*/
const observeItem = (newObserver, oldObserver) => {
if (rootRef.value) {
oldObserver?.unobserve(rootRef.value);
newObserver?.observe(rootRef.value);
if (pendingScrollTo.value === props.item.id) {
nextTick(() => {
rootRef.value.scrollIntoView({
block: 'center',
});
});
xBus.emit('ScrollRestoreSucceeded');
}
}
};
/** Detaches the observer from the rendered element to prevent memory leaks. */
onBeforeUnmount(() => {
if (rootRef.value) {
firstVisibleItemObserver?.value.unobserve(rootRef.value);
}
});
/**
* Initialise scroll behavior.
* - Observes the rendered element to detect if it is the first visible item.
* - If the rendered element matches the {@link MainScrollItem.pendingScrollTo}, scrolls the
* element into the first position of the view.
*/
onMounted(() => {
nextTick(() => {
// Mounted does not guarantee that child components are mounted too
if (firstVisibleItemObserver) {
watch(firstVisibleItemObserver, observeItem, { immediate: true });
}
});
});
return { rootRef };
},
});
export { _sfc_main as default };
//# sourceMappingURL=main-scroll-item.vue2.js.map