diff --git a/src/components/shared/form_fields/CityAutocompleteField.vue b/src/components/shared/form_fields/CityAutocompleteField.vue index b4d0fbf9e..077b28fb9 100644 --- a/src/components/shared/form_fields/CityAutocompleteField.vue +++ b/src/components/shared/form_fields/CityAutocompleteField.vue @@ -54,6 +54,7 @@ import { CityAutocompleteResource, NullCityAutocompleteResource } from '@src/api import TextFormInput from '@src/components/shared/form_elements/TextFormInput.vue'; import { updateAutocompleteScrollPosition } from '@src/components/shared/form_fields/updateAutocompleteScrollPosition'; import { useAriaDescribedby } from '@src/components/shared/form_fields/useAriaDescribedby'; +import { useAutocompleteScrollIntoViewOnFocus } from '@src/components/shared/form_fields/useAutocompleteScrollIntoViewOnFocus'; enum InteractionState { Typing, @@ -85,6 +86,7 @@ const ariaDescribedby = useAriaDescribedby( `${props.inputId}-error`, computed( () => props.showError ) ); +const scrollIntoView = useAutocompleteScrollIntoViewOnFocus( props.scrollTargetId, 769 ); const placeholder = computed( () => { if ( cities.value.length > 0 ) { @@ -93,13 +95,6 @@ const placeholder = computed( () => { return 'form_for_example'; } ); -const scrollIntoView = (): void => { - const scrollIntoViewElement = document.getElementById( props.scrollTargetId ); - if ( scrollIntoViewElement ) { - scrollIntoViewElement.scrollIntoView( { behavior: 'smooth' } ); - } -}; - const onFocus = ( event: Event ) => { autocompleteIsActive.value = true; scrollIntoView(); diff --git a/src/components/shared/form_fields/CountryAutocompleteField.vue b/src/components/shared/form_fields/CountryAutocompleteField.vue index 9e8a43de7..66ee7ffe3 100644 --- a/src/components/shared/form_fields/CountryAutocompleteField.vue +++ b/src/components/shared/form_fields/CountryAutocompleteField.vue @@ -58,6 +58,7 @@ import TextFormInput from '@src/components/shared/form_elements/TextFormInput.vu import { computed, nextTick, ref } from 'vue'; import { updateAutocompleteScrollPosition } from '@src/components/shared/form_fields/updateAutocompleteScrollPosition'; import { useAriaDescribedby } from '@src/components/shared/form_fields/useAriaDescribedby'; +import { useAutocompleteScrollIntoViewOnFocus } from '@src/components/shared/form_fields/useAutocompleteScrollIntoViewOnFocus'; enum InteractionState { Typing, @@ -94,18 +95,12 @@ const ariaDescribedby = useAriaDescribedby( `${props.inputId}-error`, computed( () => props.showError ) ); +const scrollIntoView = useAutocompleteScrollIntoViewOnFocus( props.scrollTargetId, 769 ); const isFirstFocusOnDefaultValue = (): boolean => { return !wasFocusedBefore.value && !props.wasRestored; }; -const scrollIntoView = (): void => { - const scrollIntoViewElement = document.getElementById( props.scrollTargetId ); - if ( scrollIntoViewElement ) { - scrollIntoViewElement.scrollIntoView( { behavior: 'smooth' } ); - } -}; - const onFocus = ( event: Event ) => { if ( isFirstFocusOnDefaultValue() ) { countryName.value = ''; diff --git a/src/components/shared/form_fields/StreetAutocompleteField.vue b/src/components/shared/form_fields/StreetAutocompleteField.vue index 393433efb..516b4df41 100644 --- a/src/components/shared/form_fields/StreetAutocompleteField.vue +++ b/src/components/shared/form_fields/StreetAutocompleteField.vue @@ -79,6 +79,7 @@ import { useStreetsResource } from '@src/components/shared/form_fields/useStreet import TextFormInput from '@src/components/shared/form_elements/TextFormInput.vue'; import { updateAutocompleteScrollPosition } from '@src/components/shared/form_fields/updateAutocompleteScrollPosition'; import ValueEqualsPlaceholderWarning from '@src/components/shared/ValueEqualsPlaceholderWarning.vue'; +import { useAutocompleteScrollIntoViewOnFocus } from '@src/components/shared/form_fields/useAutocompleteScrollIntoViewOnFocus'; enum InteractionState { Typing, @@ -112,6 +113,7 @@ const ariaDescribedby = useAriaDescribedby( `${props.inputIdStreetName}-error`, computed( () => props.showError ) ); +const scrollIntoView = useAutocompleteScrollIntoViewOnFocus( props.scrollTargetId, 769 ); const filteredStreets = computed>( () => { const streetList = streets.value.filter( ( streetItem: string ) => { @@ -127,13 +129,6 @@ const onUpdateModel = (): void => { emit( 'update:modelValue', joinStreetAndBuildingNumber( streetNameModel.value, buildingNumberModel.value ) ); }; -const scrollIntoView = (): void => { - const scrollIntoViewElement = document.getElementById( props.scrollTargetId ); - if ( scrollIntoViewElement ) { - scrollIntoViewElement.scrollIntoView( { behavior: 'smooth' } ); - } -}; - const onStreetNameFocus = ( event: Event ) => { autocompleteIsActive.value = true; scrollIntoView(); diff --git a/src/components/shared/form_fields/useAutocompleteScrollIntoViewOnFocus.ts b/src/components/shared/form_fields/useAutocompleteScrollIntoViewOnFocus.ts new file mode 100644 index 000000000..327f3b83c --- /dev/null +++ b/src/components/shared/form_fields/useAutocompleteScrollIntoViewOnFocus.ts @@ -0,0 +1,13 @@ +export function useAutocompleteScrollIntoViewOnFocus( target: string, maxWidth: number ): () => void { + return (): void => { + + if ( window.innerWidth > maxWidth ) { + return; + } + + const scrollIntoViewElement = document.getElementById( target ); + if ( scrollIntoViewElement ) { + scrollIntoViewElement.scrollIntoView( { behavior: 'smooth' } ); + } + }; +} diff --git a/tests/unit/components/shared/form_fields/CityAutocompleteField.spec.ts b/tests/unit/components/shared/form_fields/CityAutocompleteField.spec.ts index 76bdc3ba4..9f292284d 100644 --- a/tests/unit/components/shared/form_fields/CityAutocompleteField.spec.ts +++ b/tests/unit/components/shared/form_fields/CityAutocompleteField.spec.ts @@ -231,11 +231,21 @@ describe( 'CityAutocompleteField.vue', () => { expect( field.attributes( 'aria-describedby' ) ).toStrictEqual( 'city-selected city-error' ); } ); - it( 'scrolls field into view when focused', async () => { + it( 'scrolls field into view on small size when focused', async () => { const wrapper = getWrapper(); + Object.defineProperty( window, 'innerWidth', { writable: true, configurable: true, value: 769 } ); await wrapper.find( '#city' ).trigger( 'focus' ); expect( scrollElement.scrollIntoView ).toHaveBeenCalled(); } ); + + it( 'does not scroll field into view on large size when focused', async () => { + const wrapper = getWrapper(); + Object.defineProperty( window, 'innerWidth', { writable: true, configurable: true, value: 770 } ); + + await wrapper.find( '#city' ).trigger( 'focus' ); + + expect( scrollElement.scrollIntoView ).not.toHaveBeenCalled(); + } ); } ); diff --git a/tests/unit/components/shared/form_fields/CountryAutocompleteField.spec.ts b/tests/unit/components/shared/form_fields/CountryAutocompleteField.spec.ts index 6a4a255d5..4ed060e0b 100644 --- a/tests/unit/components/shared/form_fields/CountryAutocompleteField.spec.ts +++ b/tests/unit/components/shared/form_fields/CountryAutocompleteField.spec.ts @@ -288,11 +288,21 @@ describe( 'CountryAutocompleteField.vue', () => { expect( field.attributes( 'aria-describedby' ) ).toStrictEqual( 'country-selected country-error' ); } ); - it( 'scrolls field into view when focused', async () => { + it( 'scrolls field into view on small size when focused', async () => { const wrapper = getWrapper(); + Object.defineProperty( window, 'innerWidth', { writable: true, configurable: true, value: 769 } ); await wrapper.find( '#country' ).trigger( 'focus' ); expect( scrollElement.scrollIntoView ).toHaveBeenCalled(); } ); + + it( 'does not scroll field into view on large size when focused', async () => { + const wrapper = getWrapper(); + Object.defineProperty( window, 'innerWidth', { writable: true, configurable: true, value: 770 } ); + + await wrapper.find( '#country' ).trigger( 'focus' ); + + expect( scrollElement.scrollIntoView ).not.toHaveBeenCalled(); + } ); } ); diff --git a/tests/unit/components/shared/form_fields/StreetAutocompleteField.spec.ts b/tests/unit/components/shared/form_fields/StreetAutocompleteField.spec.ts index d51cc7c86..1e7e4c6a8 100644 --- a/tests/unit/components/shared/form_fields/StreetAutocompleteField.spec.ts +++ b/tests/unit/components/shared/form_fields/StreetAutocompleteField.spec.ts @@ -265,11 +265,21 @@ describe( 'StreetAutocompleteField.vue', () => { expect( field.attributes( 'aria-describedby' ) ).toStrictEqual( 'street-selected street-error' ); } ); - it( 'scrolls field into view when focused', async () => { + it( 'scrolls field into view on small size when focused', async () => { const wrapper = getWrapper( '', '12345' ); + Object.defineProperty( window, 'innerWidth', { writable: true, configurable: true, value: 769 } ); await wrapper.find( '#street' ).trigger( 'focus' ); expect( scrollElement.scrollIntoView ).toHaveBeenCalled(); } ); + + it( 'does not scroll field into view on large size when focused', async () => { + const wrapper = getWrapper( '', '12345' ); + Object.defineProperty( window, 'innerWidth', { writable: true, configurable: true, value: 770 } ); + + await wrapper.find( '#street' ).trigger( 'focus' ); + + expect( scrollElement.scrollIntoView ).not.toHaveBeenCalled(); + } ); } );