Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion src/autocomplete/Autocomplete.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React, { useRef, useState } from 'react';
import { FormInput } from '../formInput';
import { FormSelect } from '../formSelect';
import { ErrorMessage, Hint, Roles, useHydrated, debounce } from '../common';
Expand Down Expand Up @@ -281,6 +281,9 @@ export const Autocomplete = ({
const [showOptions, setShowOptions] = useState<boolean>(false);
const [showPrompt, setShowPrompt] = useState<boolean>(false);
const [userInput, setUserInput] = useState<string>(defaultValue);
const resultRef = useRef<HTMLLIElement[]>(null) as React.MutableRefObject<
HTMLLIElement[]
>;
let hydrated = useHydrated();

const showPromptMessage = (inputValue = userInput): boolean =>
Expand Down Expand Up @@ -393,10 +396,16 @@ export const Autocomplete = ({
return;
}
setActiveOption(activeOption - 1);
const prevItem = resultRef.current && resultRef.current[activeOption - 1];
prevItem &&
prevItem.scrollIntoView({ block: 'nearest', inline: 'start' });
} else if (evt.code === 'ArrowDown') {
if (activeOption === filterList.length - 1) {
return;
}
const nextItem = resultRef.current && resultRef.current[activeOption + 1];
nextItem &&
nextItem.scrollIntoView({ block: 'nearest', inline: 'start' });
setActiveOption(activeOption + 1);
} else if (evt.code === 'Escape') {
setShowOptions(false);
Expand Down Expand Up @@ -560,6 +569,7 @@ export const Autocomplete = ({
{searchEl}
{displayResultList() && (
<ResultList
resultLiRef={resultRef}
list={filterList}
listId={optionsId}
userInput={userInput}
Expand Down
5 changes: 5 additions & 0 deletions src/autocomplete/ResultList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react';
import { classNames } from '../common';

type ResultListProps = {
resultLiRef: React.MutableRefObject<HTMLLIElement[]>;
list: string[];
listId?: string;
userInput: string;
Expand All @@ -18,6 +19,7 @@ type ResultListProps = {
};

export const ResultList = ({
resultLiRef,
list,
listId,
userInput,
Expand Down Expand Up @@ -55,6 +57,9 @@ export const ResultList = ({
key={optionName}
onClick={onClick}
style={liContainerStyle}
ref={(ref: HTMLLIElement) => {
resultLiRef.current = { ...resultLiRef.current, [index]: ref };
}}
>
{optionName}
</li>
Expand Down
51 changes: 51 additions & 0 deletions src/autocomplete/__tests__/Autocomplete.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ const DummyAutoComplete = () => {
};

describe('Autocomplete', () => {
beforeAll(() => {
window.HTMLLIElement.prototype.scrollIntoView = jest.fn();
});

it('should display multiselect if progresive enhancement and multiselect is true', () => {
//@ts-ignore
jest.spyOn(hooks, 'useHydrated').mockImplementation(() => false);
Expand Down Expand Up @@ -354,6 +358,53 @@ describe('Autocomplete', () => {
expect(input.value).toBe('daniele');
});

it('should display the next item when you scroll with the keyboard', async () => {
const user = userEvent.setup();

render(<Autocomplete options={[
'Papaya',
'Persimmon',
'Paw Paw',
'Prickly Pear',
'Peach',
'Pomegranate',
'Pineapple 1',
'Pineapple 2',
'Pineapple 3',
'Pineapple 4',
'Pineapple 5',
'Pineapple 6',
'Pineapple 7',
'Pineapple 8',
'Pineapple 9',
'Pineapple 10',
'Pineapple 11',
'Pineapple 12',
'Pineapple 13',
'Pineapple 14'
]} />);
const input: any = screen.getByRole('textbox');
await user.type(input, 'p');
fireEvent.keyDown(input, { code: 'ArrowDown' });
fireEvent.keyDown(input, { code: 'ArrowDown' });
fireEvent.keyDown(input, { code: 'ArrowDown' });
fireEvent.keyDown(input, { code: 'ArrowDown' });
fireEvent.keyDown(input, { code: 'ArrowDown' });
fireEvent.keyDown(input, { code: 'ArrowDown' });
fireEvent.keyDown(input, { code: 'ArrowDown' });
fireEvent.keyDown(input, { code: 'ArrowDown' });
fireEvent.keyDown(input, { code: 'ArrowDown' });
fireEvent.keyDown(input, { code: 'ArrowDown' });
fireEvent.keyDown(input, { code: 'ArrowDown' });
fireEvent.keyDown(input, { code: 'ArrowDown' });

const listItems: HTMLLIElement[] = screen.getAllByRole('listitem');
const exactItem = screen.queryByText(/Pineapple 5/i);

expect(listItems[10]).toBeVisible();
expect(exactItem).toBeVisible();
});

it('should higlight the first one as active if you try to keyUp', async () => {
const user = userEvent.setup();
render(
Expand Down
13 changes: 13 additions & 0 deletions src/autocomplete/__tests__/ResultList.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,15 @@ import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import { ResultList } from '../ResultList';

const resultRef = {
current: []
};
describe('ResultList', () => {
it('should display the result content', () => {
const handleClick = jest.fn();
render(
<ResultList
resultLiRef={resultRef}
list={['daniele', 'isaac']}
userInput="d"
activeOption={1}
Expand All @@ -24,6 +28,7 @@ describe('ResultList', () => {
const handleClick = jest.fn();
const { container } = render(
<ResultList
resultLiRef={resultRef}
list={['daniele', 'isaac']}
userInput="d"
activeOption={1}
Expand All @@ -46,6 +51,7 @@ describe('ResultList', () => {
const handleClick = jest.fn();
render(
<ResultList
resultLiRef={resultRef}
list={['daniele', 'isaac']}
userInput="d"
activeOption={0}
Expand All @@ -65,6 +71,7 @@ describe('ResultList', () => {
const handleClick = jest.fn();
render(
<ResultList
resultLiRef={resultRef}
list={['daniele', 'isaac']}
userInput="d"
activeOption={1}
Expand All @@ -84,6 +91,7 @@ describe('ResultList', () => {
const handleClick = jest.fn();
const { container } = render(
<ResultList
resultLiRef={resultRef}
list={[]}
userInput="d"
activeOption={1}
Expand All @@ -100,6 +108,7 @@ describe('ResultList', () => {
const handleClick = jest.fn();
const { container } = render(
<ResultList
resultLiRef={resultRef}
list={[]}
userInput="d"
activeOption={1}
Expand All @@ -118,6 +127,7 @@ describe('ResultList', () => {
const handleClick = jest.fn();
const { container } = render(
<ResultList
resultLiRef={resultRef}
list={['firstItem']}
listId="dcx-list-id"
userInput="d"
Expand All @@ -135,6 +145,7 @@ describe('ResultList', () => {
const handleClick = jest.fn();
const { container } = render(
<ResultList
resultLiRef={resultRef}
list={['firstItem']}
userInput="d"
activeOption={1}
Expand All @@ -151,6 +162,7 @@ describe('ResultList', () => {
const handleClick = jest.fn();
const { container } = render(
<ResultList
resultLiRef={resultRef}
list={['firstItem']}
listId="dcx-list-id"
userInput="d"
Expand All @@ -168,6 +180,7 @@ describe('ResultList', () => {
const handleClick = jest.fn();
const { container } = render(
<ResultList
resultLiRef={resultRef}
list={['firstItem']}
userInput="d"
activeOption={1}
Expand Down
28 changes: 14 additions & 14 deletions stories/Autocomplete/ClassBased.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,7 @@ export default {
tags: ['autodocs']
};

const options = [
'Papaya',
'Persimmon',
'Paw Paw',
'Prickly Pear',
'Peach',
'Pomegranate',
'Pineapple',
];
const options = ["Afghanistan","Albania","Algeria","Andorra","Angola","Anguilla","Antigua &amp; Barbuda","Argentina","Armenia","Aruba","Australia","Austria","Azerbaijan","Bahamas","Bahrain","Bangladesh","Barbados","Belarus","Belgium","Belize","Benin","Bermuda","Bhutan","Bolivia","Bosnia &amp; Herzegovina","Botswana","Brazil","British Virgin Islands","Brunei","Bulgaria","Burkina Faso","Burundi","Cambodia","Cameroon","Cape Verde","Cayman Islands","Chad","Chile","China","Colombia","Congo","Cook Islands","Costa Rica","Cote D Ivoire","Croatia","Cruise Ship","Cuba","Cyprus","Czech Republic","Denmark","Djibouti","Dominica","Dominican Republic","Ecuador","Egypt","El Salvador","Equatorial Guinea","Estonia","Ethiopia","Falkland Islands","Faroe Islands","Fiji","Finland","France","French Polynesia","French West Indies","Gabon","Gambia","Georgia","Germany","Ghana","Gibraltar","Greece","Greenland","Grenada","Guam","Guatemala","Guernsey","Guinea","Guinea Bissau","Guyana","Haiti","Honduras","Hong Kong","Hungary","Iceland","India","Indonesia","Iran","Iraq","Ireland","Isle of Man","Israel","Italy","Jamaica","Japan","Jersey","Jordan","Kazakhstan","Kenya","Kuwait","Kyrgyz Republic","Laos","Latvia","Lebanon","Lesotho","Liberia","Libya","Liechtenstein","Lithuania","Luxembourg","Macau","Macedonia","Madagascar","Malawi","Malaysia","Maldives","Mali","Malta","Mauritania","Mauritius","Mexico","Moldova","Monaco","Mongolia","Montenegro","Montserrat","Morocco","Mozambique","Namibia","Nepal","Netherlands","Netherlands Antilles","New Caledonia","New Zealand","Nicaragua","Niger","Nigeria","Norway","Oman","Pakistan","Palestine","Panama","Papua New Guinea","Paraguay","Peru","Philippines","Poland","Portugal","Puerto Rico","Qatar","Reunion","Romania","Russia","Rwanda","Saint Pierre &amp; Miquelon","Samoa","San Marino","Satellite","Saudi Arabia","Senegal","Serbia","Seychelles","Sierra Leone","Singapore","Slovakia","Slovenia","South Africa","South Korea","Spain","Sri Lanka","St Kitts &amp; Nevis","St Lucia","St Vincent","St. Lucia","Sudan","Suriname","Swaziland","Sweden","Switzerland","Syria","Taiwan","Tajikistan","Tanzania","Thailand","Timor L'Este","Togo","Tonga","Trinidad &amp; Tobago","Tunisia","Turkey","Turkmenistan","Turks &amp; Caicos","Uganda","Ukraine","United Arab Emirates","United Kingdom","Uruguay","Uzbekistan","Venezuela","Vietnam","Virgin Islands (US)","Yemen","Zambia","Zimbabwe"];

export const Basic = {
name: 'Basic',
Expand All @@ -39,6 +31,7 @@ export const Basic = {
resultNoOptionClass:"resultNoOptionClass",
resultActiveClass:"autocomplete__option",
notFoundText:"No fruit found",
resultActiveClass:"autocomplete__option--focused"
},
};

Expand All @@ -56,14 +49,15 @@ export const Hint = {
resultNoOptionClass:"resultNoOptionClass",
resultActiveClass:"autocomplete__option",
notFoundText:"No fruit found",
resultActiveClass:"autocomplete__option--focused"
},
};

/**
* Before the autocomplete appear you need to type at least 2 character
*/
export const MinChars = {
name: 'Hint',
name: 'MinChars',
args: {
options: options,
minCharsBeforeSearch:2,
Expand All @@ -76,6 +70,7 @@ export const MinChars = {
resultNoOptionClass:"resultNoOptionClass",
resultActiveClass:"autocomplete__option",
notFoundText:"No fruit found",
resultActiveClass:"autocomplete__option--focused"
},
};

Expand All @@ -93,7 +88,8 @@ export const Defaultvalue = {
resultNoOptionClass:"resultNoOptionClass",
resultActiveClass:"autocomplete__option",
notFoundText:"No fruit found",
defaultValue:"Papaya"
defaultValue:"Papaya",
resultActiveClass:"autocomplete__option--focused"
},
};

Expand All @@ -112,7 +108,7 @@ export const NoResult = {
resultNoOptionClass:"resultNoOptionClass",
resultActiveClass:"autocomplete__option",
notFoundText:"No fruit found",
notFoundText:"No fruit found"
resultActiveClass:"autocomplete__option--focused"
},
};

Expand All @@ -133,6 +129,7 @@ export const Placeholder = {
resultNoOptionClass:"resultNoOptionClass",
resultActiveClass:"autocomplete__option",
notFoundText:"No fruit found",
resultActiveClass:"autocomplete__option--focused"
},
};

Expand All @@ -150,6 +147,7 @@ export const WithLabel = {
resultActiveClass:"autocomplete__option",
notFoundText:"No fruit found",
labelText:"Search for a fruit",
resultActiveClass:"autocomplete__option--focused"
},
};

Expand Down Expand Up @@ -181,7 +179,8 @@ export const WithError = {
text: 'Error:',
className: 'govuk-visually-hidden',
},
id:"fruit-search"
id:"fruit-search",
resultActiveClass:"autocomplete__option--focused"
},
};

Expand Down Expand Up @@ -228,6 +227,7 @@ export const WithCustomSearch = {
text: 'Error:',
className: 'govuk-visually-hidden',
},
id:"fruit-search"
id:"fruit-search",
resultActiveClass:"autocomplete__option--focused"
},
};
8 changes: 8 additions & 0 deletions stories/govUkStyle.css
Original file line number Diff line number Diff line change
Expand Up @@ -1247,6 +1247,14 @@
outline: 0;
}

.autocomplete__option--focused,
.autocomplete__option:hover {
background-color: #1d70b8;
border-color: #1d70b8;
color: white;
outline: none;
}

.govuk-button {
font-family: 'GDS Transport', arial, sans-serif;
font-weight: 400;
Expand Down