Skip to content

Commit

Permalink
Merge pull request #496 from wmde/fix-desktop-autocomplete-autoscroll
Browse files Browse the repository at this point in the history
Make autocomplete autoscroll on focus mobile only
  • Loading branch information
Abban authored Sep 13, 2024
2 parents ad5e8da + ea52ef7 commit 320f06e
Show file tree
Hide file tree
Showing 7 changed files with 54 additions and 24 deletions.
9 changes: 2 additions & 7 deletions src/components/shared/form_fields/CityAutocompleteField.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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 { autoscrollMaxWidth, useAutocompleteScrollIntoViewOnFocus } from '@src/components/shared/form_fields/useAutocompleteScrollIntoViewOnFocus';
enum InteractionState {
Typing,
Expand Down Expand Up @@ -85,6 +86,7 @@ const ariaDescribedby = useAriaDescribedby(
`${props.inputId}-error`,
computed<boolean>( () => props.showError )
);
const scrollIntoView = useAutocompleteScrollIntoViewOnFocus( props.scrollTargetId, autoscrollMaxWidth );
const placeholder = computed( () => {
if ( cities.value.length > 0 ) {
Expand All @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 { autoscrollMaxWidth, useAutocompleteScrollIntoViewOnFocus } from '@src/components/shared/form_fields/useAutocompleteScrollIntoViewOnFocus';
enum InteractionState {
Typing,
Expand Down Expand Up @@ -94,18 +95,12 @@ const ariaDescribedby = useAriaDescribedby(
`${props.inputId}-error`,
computed<boolean>( () => props.showError )
);
const scrollIntoView = useAutocompleteScrollIntoViewOnFocus( props.scrollTargetId, autoscrollMaxWidth );
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 = '';
Expand Down
9 changes: 2 additions & 7 deletions src/components/shared/form_fields/StreetAutocompleteField.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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 { autoscrollMaxWidth, useAutocompleteScrollIntoViewOnFocus } from '@src/components/shared/form_fields/useAutocompleteScrollIntoViewOnFocus';
enum InteractionState {
Typing,
Expand Down Expand Up @@ -112,6 +113,7 @@ const ariaDescribedby = useAriaDescribedby(
`${props.inputIdStreetName}-error`,
computed<boolean>( () => props.showError )
);
const scrollIntoView = useAutocompleteScrollIntoViewOnFocus( props.scrollTargetId, autoscrollMaxWidth );
const filteredStreets = computed<Array<string>>( () => {
const streetList = streets.value.filter( ( streetItem: string ) => {
Expand All @@ -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();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export const autoscrollMaxWidth = 769;

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' } );
}
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<HTMLInputElement>( '#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<HTMLInputElement>( '#city' ).trigger( 'focus' );

expect( scrollElement.scrollIntoView ).not.toHaveBeenCalled();
} );
} );
Original file line number Diff line number Diff line change
Expand Up @@ -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<HTMLInputElement>( '#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<HTMLInputElement>( '#country' ).trigger( 'focus' );

expect( scrollElement.scrollIntoView ).not.toHaveBeenCalled();
} );
} );
Original file line number Diff line number Diff line change
Expand Up @@ -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<HTMLInputElement>( '#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<HTMLInputElement>( '#street' ).trigger( 'focus' );

expect( scrollElement.scrollIntoView ).not.toHaveBeenCalled();
} );
} );

0 comments on commit 320f06e

Please sign in to comment.