UNPKG

@empathyco/x-components

Version:
85 lines (82 loc) 3.17 kB
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