Skip to content

Commit

Permalink
feat(Dropdown): Add label icon
Browse files Browse the repository at this point in the history
Feature was in the original designs.
  • Loading branch information
thyhjwb6 committed Oct 29, 2020
1 parent 2cbf9c6 commit 98f9818
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 9 deletions.
7 changes: 7 additions & 0 deletions packages/docs-site/src/library/pages/components/dropdown.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,13 @@ The `Dropdown` accepts a label, options and a handler which is called with the v
Default: '',
Description: 'The text to display in the component the user needs to click on to view options',
},
{
Name: 'labelIcon',
Type: 'React.ReactNode',
Required: 'False',
Default: '',
Description: 'Optionally display an icon before the label text',
},
{
Name: 'onSelect',
Type: '(value:string) => void',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react'
import { action } from '@storybook/addon-actions'
import { IconLayers } from '@royalnavy/icon-library'
import { storiesOf } from '@storybook/react'
import React from 'react'

import { Bell, Tools } from '../../icons'
import { Dropdown } from './Dropdown'
Expand Down Expand Up @@ -47,6 +48,7 @@ examples.add('Icons', () => (
<Dropdown
options={iconOptions}
label="Layers"
labelIcon={<IconLayers />}
onSelect={action('onSelect')}
/>
))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
import React from 'react'
import '@testing-library/jest-dom/extend-expect'
import { IconLayers } from '@royalnavy/icon-library'
import { render, RenderResult, fireEvent } from '@testing-library/react'

import { Dropdown } from './Dropdown'

const options = [
{ label: 'Option 1', value: '1' },
{ label: 'Option 2', value: '2' },
{ label: 'Option 3', value: '3' },
]

describe('Dropdown', () => {
let wrapper: RenderResult
let onSelectSpy: (value: string) => void
Expand All @@ -12,23 +19,24 @@ describe('Dropdown', () => {
beforeEach(() => {
onSelectSpy = jest.fn()

const options = [
{ label: 'Option 1', value: '1' },
{ label: 'Option 2', value: '2' },
{ label: 'Option 3', value: '3' },
]

wrapper = render(
<Dropdown
onSelect={onSelectSpy}
options={options}
label="Dropdown label"
labelIcon={<IconLayers />}
/>
)
})

it('should render the label icon', () => {
expect(wrapper.getByTestId('placeholder-icon')).toBeInTheDocument()
})

it('should render the label', () => {
expect(wrapper.getByText('Dropdown label')).toBeInTheDocument()
expect(wrapper.getByTestId('placeholder-label')).toHaveTextContent(
'Dropdown label'
)
})

it('should set the ARIA attributes on the input', () => {
Expand Down Expand Up @@ -65,4 +73,26 @@ describe('Dropdown', () => {
})
})
})

describe('minimal props', () => {
beforeEach(() => {
onSelectSpy = jest.fn()

wrapper = render(
<Dropdown
onSelect={onSelectSpy}
options={options}
label="Dropdown label"
/>
)
})

it('should render the label', () => {
expect(wrapper.getByTestId('placeholder-label')).toBeInTheDocument()
})

it('should not render the label icon', () => {
expect(wrapper.queryAllByTestId('placeholder-icon')).toHaveLength(0)
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ import styled from 'styled-components'
import { DropdownIndicator } from './DropdownIndicator'
import { DropdownLabel } from './DropdownLabel'
import { DropdownOption } from './DropdownOption'
import { DropdownPlaceholder } from './DropdownPlaceholder'

const { color, spacing } = selectors

export interface DropdownProps {
onSelect: (value: string) => void
options: DropdownOption[]
label: string
labelIcon?: React.ReactNode
}

const StyledSelect = styled(Select)`
Expand Down Expand Up @@ -120,6 +122,7 @@ export const Dropdown: React.FC<DropdownProps> = ({
onSelect,
options,
label,
...rest
}) => {
const onChange = (option: ValueType<DropdownOption>) => {
const dropdownOption = option as DropdownOption
Expand All @@ -130,13 +133,14 @@ export const Dropdown: React.FC<DropdownProps> = ({
<StyledSelect
aria-label={label}
classNamePrefix="rn-dropdown"
components={{ DropdownIndicator }}
components={{ DropdownIndicator, Placeholder: DropdownPlaceholder }}
controlShouldRenderValue={false}
formatOptionLabel={DropdownLabel}
isSearchable={false}
options={options}
onChange={onChange}
placeholder={label}
{...rest}
/>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React from 'react'
import { components } from 'react-select'
import styled from 'styled-components'
import { selectors } from '@royalnavy/design-tokens'

const { spacing } = selectors

const StyledIcon = styled.span`
position: relative;
top: ${spacing('px')};
`

const StyledLabel = styled.span`
${StyledIcon} + & {
margin-left: ${spacing('3')};
}
`

export const DropdownPlaceholder: React.FC<any> = (props) => {
const {
selectProps: { labelIcon: icon },
} = props

return (
<components.Placeholder {...props}>
{icon && <StyledIcon data-testid="placeholder-icon">{icon}</StyledIcon>}
<StyledLabel data-testid="placeholder-label">
{props.children}
</StyledLabel>
</components.Placeholder>
)
}

DropdownPlaceholder.displayName = 'DropdownPlaceholder'

0 comments on commit 98f9818

Please sign in to comment.