Repository: directus/directus
File: app/src/views/private/components/overlay-item-content.vue (Vue)

Code before:
		return collection === 'directus_files' || relatedCollection === 'directus_files';
	});

	const file = computed(() => {
		if (isDirectusFiles.value === false) return null;

		const fileData = junctionField ? junctionInitialValues.value : mainInitialValues.value;

		return fileData || null;
	});

	return { file, isDirectusFiles };
}

function useValidationScrollToField() {
	const mainFormEl = useTemplateRef<any>('mainForm');
	const junctionFormEl = useTemplateRef<any>('junctionForm');
	const mainDrawerElement = inject<Ref<HTMLElement | null>>('main-element');

	watch(
		() => validationErrors,
		(newVal, oldVal) => {
			if (isEqual(newVal, oldVal)) return;
			if (newVal?.length > 0) mainDrawerElement?.value?.scrollTo({ top: 0, behavior: 'smooth' });
		},
	);

	return { scrollToField };

	function scrollToField(fieldKey: string) {
		const fieldOfMainForm = fields.find((field: Field) => field.field === fieldKey);

		if (fieldOfMainForm) {
			mainFormEl.value?.$refs?.el?.scrollIntoView({ behavior: 'smooth' });
			return;
		}

		junctionFormEl.value?.$refs?.el?.scrollIntoView({ behavior: 'smooth' });
	}
}
</script>

<template>
	<div class="overlay-item-content" :class="{ empty: emptyForm }">
		<FilePreviewReplace v-if="file" class="preview" :disabled :non-editable :file in-modal @replace="refresh" />

		<VInfo v-if="emptyForm" :title="$t('no_visible_fields')" icon="search" center>
			{{ $t('no_visible_fields_copy') }}
		</VInfo>

		<div v-else class="overlay-item-order" :class="{ swap: swapFormOrder }">

Review comment (suggestion):
The watcher here lives inside `useValidationScrollToField` which addresses a different concern. The logic here ensures that when we click on a field in the ValidationErrors, that the field is scrolled into the view. However, scrolling to the ValidationErrors when they are not in the view is a different concern. Therefore, either place the watcher outside the composable or consider renaming it so it to address both concerns.

Code after:

	const junctionInitialValues = computed(() => {
		if (!initialValues || !junctionField || !initialValues[junctionField]) return null;
		return initialValues[junctionField];
	});

	return {
		mainInitialValues,
		junctionInitialValues,
	};
}

function useFile() {
	const isDirectusFiles = computed(() => {
		return collection === 'directus_files' || relatedCollection === 'directus_files';
	});

	const file = computed(() => {
		if (isDirectusFiles.value === false) return null;

		const fileData = junctionField ? junctionInitialValues.value : mainInitialValues.value;

		return fileData || null;
	});

	return { file, isDirectusFiles };
}

function useValidationScrollToField() {
	const mainFormEl = useTemplateRef<any>('mainForm');
	const junctionFormEl = useTemplateRef<any>('junctionForm');

	return { scrollToField };

	function scrollToField(fieldKey: string) {
		const fieldOfMainForm = fields.find((field: Field) => field.field === fieldKey);

		if (fieldOfMainForm) {
			mainFormEl.value?.$refs?.el?.scrollIntoView({ behavior: 'smooth' });
			return;
		}

		junctionFormEl.value?.$refs?.el?.scrollIntoView({ behavior: 'smooth' });
	}
}
</script>

<template>
	<div class="overlay-item-content" :class="{ empty: emptyForm }">
		<FilePreviewReplace v-if="file" class="preview" :disabled :non-editable :file in-modal @replace="refresh" />