diff --git a/packages/docs-site/src/library/pages/components/dropdown.md b/packages/docs-site/src/library/pages/components/dropdown.md index 45ccf65303..d845c182c4 100644 --- a/packages/docs-site/src/library/pages/components/dropdown.md +++ b/packages/docs-site/src/library/pages/components/dropdown.md @@ -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', diff --git a/packages/react-component-library/src/components/Dropdown/Dropdown.stories.tsx b/packages/react-component-library/src/components/Dropdown/Dropdown.stories.tsx index f747bf5e38..c9c1a557f5 100644 --- a/packages/react-component-library/src/components/Dropdown/Dropdown.stories.tsx +++ b/packages/react-component-library/src/components/Dropdown/Dropdown.stories.tsx @@ -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' @@ -47,6 +48,7 @@ examples.add('Icons', () => ( } onSelect={action('onSelect')} /> )) diff --git a/packages/react-component-library/src/components/Dropdown/Dropdown.test.tsx b/packages/react-component-library/src/components/Dropdown/Dropdown.test.tsx index 85df7c9462..c2b6f3d5f9 100644 --- a/packages/react-component-library/src/components/Dropdown/Dropdown.test.tsx +++ b/packages/react-component-library/src/components/Dropdown/Dropdown.test.tsx @@ -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 @@ -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( } /> ) }) + 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', () => { @@ -65,4 +73,26 @@ describe('Dropdown', () => { }) }) }) + + describe('minimal props', () => { + beforeEach(() => { + onSelectSpy = jest.fn() + + wrapper = render( + + ) + }) + + 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) + }) + }) }) diff --git a/packages/react-component-library/src/components/Dropdown/Dropdown.tsx b/packages/react-component-library/src/components/Dropdown/Dropdown.tsx index 30ab0573ec..5919bab58a 100644 --- a/packages/react-component-library/src/components/Dropdown/Dropdown.tsx +++ b/packages/react-component-library/src/components/Dropdown/Dropdown.tsx @@ -7,6 +7,7 @@ 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 @@ -14,6 +15,7 @@ export interface DropdownProps { onSelect: (value: string) => void options: DropdownOption[] label: string + labelIcon?: React.ReactNode } const StyledSelect = styled(Select)` @@ -120,6 +122,7 @@ export const Dropdown: React.FC = ({ onSelect, options, label, + ...rest }) => { const onChange = (option: ValueType) => { const dropdownOption = option as DropdownOption @@ -130,13 +133,14 @@ export const Dropdown: React.FC = ({ ) } diff --git a/packages/react-component-library/src/components/Dropdown/DropdownPlaceholder.tsx b/packages/react-component-library/src/components/Dropdown/DropdownPlaceholder.tsx new file mode 100644 index 0000000000..ca57759dfa --- /dev/null +++ b/packages/react-component-library/src/components/Dropdown/DropdownPlaceholder.tsx @@ -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 = (props) => { + const { + selectProps: { labelIcon: icon }, + } = props + + return ( + + {icon && {icon}} + + {props.children} + + + ) +} + +DropdownPlaceholder.displayName = 'DropdownPlaceholder'