Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

♻️ Refactor Search to use new InputWrapper #2481

Merged
merged 9 commits into from
Sep 13, 2022
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
1 change: 1 addition & 0 deletions packages/eds-core-react/src/components/Input/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const Container = styled.div(({ token, disabled, readOnly }: StyledProps) => {
--eds-input-color: ${token.typography.color};
position: relative;
height: ${token.height};
width: ${token.width};
display: flex;
flex-direction: row;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ exports[`Input Matches snapshot 1`] = `
--eds-input-adornment-color: var(--eds_text__static_icons__tertiary,rgba(111,111,111,1));
--eds-input-color: var(--eds_text__static_icons__default,rgba(61,61,61,1));
position: relative;
height: 36px;
width: 100%;
display: -webkit-box;
display: -webkit-flex;
Expand Down
29 changes: 8 additions & 21 deletions packages/eds-core-react/src/components/Search/Search.docs.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -20,35 +20,22 @@ Allows users to locate or refine content based on simple words or phrases.

`Search` can be used as a primary way of discovering content.

<ul>
<li>Search placeholder text should always say "Search".</li>
<li>Search should replace the center custom content, placeholder of the top bar.</li>
<li>Search can be a button icon that is expanded into the search field if search is less common in the application.</li>
</ul>

```tsx
import { Search } from '@equinor/eds-core-react'

<Serach />
<form>
<Search aria-label="Search for something"/>
</form>
```

## Examples

### With `onFocus` and `onBlur`

<Story id="inputs-search--with-on-focus-and-blur" />
## Accessibility

### With predefined value
* Use either a `label` or `aria-label` for description of whats being searched
* `Search` should be used inside a `form`

<Story id="inputs-search--with-predefined-value" />
<Story id="inputs-search--accessibility" />

### Centered and styled

<Story id="inputs-search--centered-and-styled" />

### Inside a form element

<Story id="inputs-search--inside-a-form" />
## Examples

### Disabled

Expand Down
137 changes: 21 additions & 116 deletions packages/eds-core-react/src/components/Search/Search.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,40 +1,9 @@
import { useState, useEffect } from 'react'
import { action } from '@storybook/addon-actions'
import styled from 'styled-components'
import {
Search,
Typography,
Button,
SearchProps,
EdsProvider,
Density,
} from '../..'
import { Search, Button, SearchProps, EdsProvider, Density } from '../..'
import { Story, ComponentMeta } from '@storybook/react'
import page from './Search.docs.mdx'

const Columns = styled.div`
display: grid;
width: 100%;
grid-gap: 16px;
grid-auto-flow: column;
grid-auto-columns: max-content;
`

const Wrapper = styled.div`
background: lightblue;
padding: 8px;
width: 50%;
height: 100px;
display: flex;
align-items: center;
justify-content: center;
`

const StyledSearch = styled(Search)`
width: 50%;
margin-left: 32px;
`

export default {
title: 'Inputs/Search',
component: Search,
Expand All @@ -46,8 +15,6 @@ export default {
} as ComponentMeta<typeof Search>

const handleOnChange = action('onChange')
const handleOnBlur = action('onBlur')
const handleOnFocus = action('onFocus')

export const Introduction: Story<SearchProps> = () => {
// This story is not interactive, because Search has no props beyond the default HTML ones.
Expand All @@ -61,80 +28,21 @@ export const Introduction: Story<SearchProps> = () => {
)
}

export const WithOnFocusAndBlur: Story<SearchProps> = () => {
const [isFocused, setIsFocused] = useState(false)

const handleFocus = () => {
setIsFocused(true)
handleOnFocus()
}

const handleBlur = () => {
setIsFocused(false)
handleOnBlur()
}

return (
<div
style={{
background: isFocused ? 'cyan' : 'transparent',
}}
>
<Typography variant="h4" as="h2">
I am connected to the search input
</Typography>
<Search
aria-label="Focused and not focused"
id="search-focusedAndNot"
placeholder="Search"
onChange={handleOnChange}
onFocus={handleFocus}
onBlur={handleBlur}
/>
</div>
)
}
WithOnFocusAndBlur.storyName = 'With on focus and blur'

export const WithPredefinedValue: Story<SearchProps> = () => (
<Search
aria-label="predefined"
id="search-predefined"
placeholder="Search"
onChange={handleOnChange}
defaultValue="Predefined value"
/>
)
WithPredefinedValue.storyName = 'With predefined value'

export const CenteredAndStyled: Story<SearchProps> = () => (
<Wrapper>
50% width
<StyledSearch
aria-label="contained"
id="search-contained"
export const accessibility: Story<SearchProps> = () => (
<form action="/">
<Search
placeholder="Search"
aria-label="Search for example items"
onChange={handleOnChange}
/>
</Wrapper>
)
CenteredAndStyled.storyName = 'Centered and styled'

export const InsideAForm: Story<SearchProps> = () => (
<form action="/">
<Search placeholder="Search" onChange={handleOnChange} />
</form>
)
InsideAForm.storyName = 'Inside a form element'

export const Disabled: Story<SearchProps> = () => (
<Search
aria-label="disabled"
id="search-disabled"
placeholder="Search"
onChange={handleOnChange}
onFocus={handleOnFocus}
onBlur={handleOnBlur}
disabled
/>
)
Expand All @@ -152,24 +60,21 @@ export const Controlled: Story<SearchProps> = () => {

return (
<>
<Typography variant="body_short">Value: {searchValue}</Typography>
<Columns>
<Search
aria-label="external set value"
id="search-external"
placeholder="Say hello! 🙋"
onChange={handleOnSearchValueChange}
value={searchValue}
/>
<Button
onClick={() => {
setSearchValue('Hello search! 👋')
action('Set search value')()
}}
>
Say hello to search!
</Button>
</Columns>
<Search
id="search-external"
aria-label="Search for Hello!"
placeholder="Say hello! 🙋"
onChange={handleOnSearchValueChange}
value={searchValue}
/>
<Button
onClick={() => {
setSearchValue('Hello search! 👋')
action('Set search value')()
}}
>
Say hello to search!
</Button>
</>
)
}
Expand All @@ -185,7 +90,7 @@ export const Compact: Story<SearchProps> = () => {
return (
<EdsProvider density={density}>
<Search
aria-label="compact"
aria-label="compact search example"
id="search-compact"
placeholder="Search"
onChange={handleOnChange}
Expand Down
49 changes: 29 additions & 20 deletions packages/eds-core-react/src/components/Search/Search.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ describe('Search', () => {
const { getComputedStyle } = window
window.getComputedStyle = (elt) => getComputedStyle(elt)

const { container } = render(<Search />)
const { container } = render(
<Search aria-label="Expect user to declare label" />,
)
await act(async () => {
const result = await axe(container)
expect(result).toHaveNoViolations()
Expand All @@ -37,11 +39,11 @@ describe('Search', () => {
it('Has rendered provided value in input field', () => {
const value = 'provided value'

render(<Search value={value} />)
render(<Search value={value} data-testid="search" />)

const searchBox = screen.queryByRole('searchbox')
const searchInput = screen.getByTestId('search')

expect(searchBox).toHaveValue(value)
expect(searchInput).toHaveValue(value)
})
it('Has called onChange once with event & new value, when value is changed', () => {
const searchId = 'search-id-when-testing'
Expand All @@ -54,11 +56,16 @@ describe('Search', () => {
})

render(
<Search id={searchId} value="some old value" onChange={handleOnChange} />,
<Search
id={searchId}
value="some old value"
onChange={handleOnChange}
data-testid="search"
/>,
)
const searchBox = screen.queryByRole('searchbox')
const searchInput = screen.queryByTestId('search')

fireEvent.change(searchBox, {
fireEvent.change(searchInput, {
target: { value: newValue },
})

Expand All @@ -81,15 +88,15 @@ describe('Search', () => {
id={searchId}
defaultValue="initial value"
onChange={handleOnChange}
data-testid="search"
/>,
)
const clearButton = screen.queryByRole('button')
const searchBox = screen.queryByRole('searchbox')

const searchInput = screen.queryByTestId('search')
fireEvent.click(clearButton)

expect(handleOnChange).toHaveBeenCalled()
expect(searchBox).toHaveValue('')
expect(searchInput).toHaveValue('')
expect(callbackValue).toEqual('')
expect(callbackId).toEqual(searchId)
})
Expand All @@ -101,10 +108,12 @@ describe('Search', () => {
callbackId = id as string
})

render(<Search id={searchId} onFocus={handleOnFocus} />)
const searchBox = screen.queryByRole('searchbox')
render(
<Search id={searchId} onFocus={handleOnFocus} data-testid="search" />,
)
const searchInput = screen.queryByTestId('search')

fireEvent.focus(searchBox)
fireEvent.focus(searchInput)

expect(handleOnFocus).toHaveBeenCalled()
expect(callbackId).toEqual(searchId)
Expand All @@ -116,22 +125,22 @@ describe('Search', () => {
callbackId = id as string
})

render(<Search id={searchId} onBlur={handleOnBlur} />)
const searchBox = screen.queryByRole('searchbox')
render(<Search id={searchId} onBlur={handleOnBlur} data-testid="search" />)
const searchInput = screen.queryByTestId('search')

fireEvent.blur(searchBox)
fireEvent.blur(searchInput)

expect(handleOnBlur).toHaveBeenCalled()
expect(callbackId).toEqual(searchId)
})

it('Has new value, when value property is changed after first render', () => {
const { rerender } = render(<Search value="old" />)
const { rerender } = render(<Search value="old" data-testid="search-old" />)

rerender(<Search value="new" />)
rerender(<Search value="new" data-testid="search-new" />)

const searchBox: HTMLInputElement = screen.queryByRole('searchbox')
const searchInput: HTMLInputElement = screen.queryByTestId('search-new')

expect(searchBox.value).toEqual('new')
expect(searchInput.value).toEqual('new')
})
})
Loading