Skip to content
This repository was archived by the owner on Mar 4, 2020. It is now read-only.

feat(dropdown): inline prop #863

Merged
merged 8 commits into from
Feb 8, 2019
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 CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- Add multiple selection flavor for `Dropdown` component @Bugaa92 ([#845](https://github.com/stardust-ui/react/pull/845))
- Add `black` and `white` options for the `color` prop of the `Label` component @mnajdova ([#855](https://github.com/stardust-ui/react/pull/855))
- Add `Flex` component @kuzhelov ([#802](https://github.com/stardust-ui/react/pull/802))
- Add `inline` prop for `Dropdown` component @Bugaa92 ([#863](https://github.com/stardust-ui/react/pull/863))

### Fixes
- Focus the last focused element which triggered `Popup` on ESC @sophieH29 ([#861](https://github.com/stardust-ui/react/pull/861))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import * as React from 'react'
import { Dropdown, Header } from '@stardust-ui/react'

const inputItems = [
'Bruce Wayne',
'Natasha Romanoff',
'Steven Strange',
'Alfred Pennyworth',
`Scarlett O'Hara`,
'Imperator Furiosa',
'Bruce Banner',
'Peter Parker',
'Selina Kyle',
]

const DropdownExampleInline = () => (
<>
<Header as="h3">Inline:</Header>
<div>
Some text inline with the{' '}
<Dropdown inline items={inputItems} placeholder="Select your hero" /> and more text.
</div>
<Header as="h3">Inline Search:</Header>
<span>
Some other text inline with the{' '}
<Dropdown
inline
search
items={inputItems}
noResultsMessage="We couldn't find any matches."
placeholder="Start typing a name"
/>{' '}
and more text.
</span>
</>
)

export default DropdownExampleInline
5 changes: 5 additions & 0 deletions docs/src/examples/components/Dropdown/Types/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ const Types = () => (
description="A dropdown can be searchable."
examplePath="components/Dropdown/Types/DropdownExampleSearch"
/>
<ComponentExample
title="Inline"
description="A dropdown can be used inline with text."
examplePath="components/Dropdown/Types/DropdownExampleInline"
/>
</ExampleSection>
)

Expand Down
10 changes: 8 additions & 2 deletions packages/react/src/components/Dropdown/Dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ export interface DropdownProps extends UIComponentProps<DropdownProps, DropdownS
*/
getA11yStatusMessage?: (options: DownshiftA11yStatusMessageOptions<ShorthandValue>) => string

/** A dropdown can be formatted to appear inline in the content of other components. */
inline?: boolean

/** Array of props for generating list options (Dropdown.Item[]) and selected item labels(Dropdown.SelectedItem[]), if it's a multiple selection. */
items?: ShorthandValue[]

Expand Down Expand Up @@ -190,6 +193,7 @@ class Dropdown extends AutoControlledComponent<Extendable<DropdownProps>, Dropdo
fluid: PropTypes.bool,
getA11ySelectionMessage: PropTypes.object,
getA11yStatusMessage: PropTypes.func,
inline: PropTypes.bool,
items: customPropTypes.collectionShorthand,
itemToString: PropTypes.func,
loading: PropTypes.bool,
Expand Down Expand Up @@ -333,11 +337,12 @@ class Dropdown extends AutoControlledComponent<Extendable<DropdownProps>, Dropdo
styles: ComponentSlotStylesInput,
getToggleButtonProps: (options?: GetToggleButtonPropsOptions) => any,
): JSX.Element {
const { triggerButton } = this.props
const content = this.getSelectedItemAsString(this.state.value)

return (
<Ref innerRef={this.buttonRef}>
{Button.create(this.props.triggerButton, {
{Button.create(triggerButton, {
defaultProps: {
className: Dropdown.slotClassNames.triggerButton,
content,
Expand Down Expand Up @@ -369,7 +374,7 @@ class Dropdown extends AutoControlledComponent<Extendable<DropdownProps>, Dropdo
) => void,
variables,
): JSX.Element {
const { searchInput, multiple, placeholder } = this.props
const { inline, searchInput, multiple, placeholder } = this.props
const { searchQuery, value } = this.state

const noPlaceholder =
Expand All @@ -378,6 +383,7 @@ class Dropdown extends AutoControlledComponent<Extendable<DropdownProps>, Dropdo
return DropdownSearchInput.create(searchInput || {}, {
defaultProps: {
placeholder: noPlaceholder ? '' : placeholder,
inline,
variables,
inputRef: this.inputRef,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ import { UIComponentProps } from '../../lib/commonPropInterfaces'
import Input from '../Input/Input'

export interface DropdownSearchInputProps extends UIComponentProps<DropdownSearchInputProps> {
/** A dropdown search input can be formatted to appear inline in the context of a Dropdown. */
inline?: boolean

/** Ref for input DOM node. */
inputRef?: React.Ref<HTMLElement>

Expand Down Expand Up @@ -70,7 +73,7 @@ class DropdownSearchInput extends UIComponent<ReactProps<DropdownSearchInputProp
}),
accessibilityInputProps: PropTypes.object,
accessibilityComboboxProps: PropTypes.object,
hasToggleButton: PropTypes.bool,
inline: PropTypes.bool,
inputRef: customPropTypes.ref,
onFocus: PropTypes.func,
onInputBlur: PropTypes.func,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
import { ComponentSlotStylesInput, ICSSInJSStyle } from '../../../types'
import { DropdownVariables } from './dropdownVariables'
import { DropdownItemProps } from '../../../../components/Dropdown/DropdownItem'
import ListItem from '../../../../components/List/ListItem'

const dropdownItemStyles: ComponentSlotStylesInput<DropdownItemProps, DropdownVariables> = {
root: ({ variables: v, props: { active } }): ICSSInJSStyle => ({
[`&.${ListItem.className}`]: { backgroundColor: v.listItemBackgroundColor },

...(active && {
[`&.${ListItem.className}`]: {
backgroundColor: v.listItemBackgroundColorActive,
color: v.listItemColorActive,
},
root: ({ props: p, variables: v }): ICSSInJSStyle => ({
whiteSpace: 'nowrap',
backgroundColor: v.listItemBackgroundColor,
...(p.active && {
color: v.listItemColorActive,
backgroundColor: v.listItemBackgroundColorActive,
}),
}),
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,14 @@ const dropdownSearchInputStyles: ComponentSlotStylesInput<
flexGrow: 1,
}),

input: ({ variables: v }): ICSSInJSStyle => ({
input: ({ props: p }): ICSSInJSStyle => ({
width: '100%',
backgroundColor: v.backgroundColor,
backgroundColor: 'transparent',
borderWidth: 0,
...(p.inline && {
paddingLeft: 0,
paddingRight: 0,
}),
}),
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,58 @@ import { DropdownProps, DropdownState } from '../../../../components/Dropdown/Dr
import { DropdownVariables } from './dropdownVariables'
import { pxToRem } from '../../../../lib'

const dropdownStyles: ComponentSlotStylesInput<DropdownProps & DropdownState, DropdownVariables> = {
root: (): ICSSInJSStyle => ({}),
type DropdownPropsAndState = DropdownProps & DropdownState

const transparentColorStyle: ICSSInJSStyle = {
backgroundColor: 'transparent',
borderColor: 'transparent',
borderBottomColor: 'transparent',
}

const transparentColorStyleObj: ICSSInJSStyle = {
...transparentColorStyle,
':hover': transparentColorStyle,
':active': transparentColorStyle,
':focus': {
...transparentColorStyle,
':active': transparentColorStyle,
},
}

const getWidth = (p: DropdownPropsAndState, v: DropdownVariables): string => {
if (p.fluid) {
return '100%'
}

if (p.inline) {
return 'initial'
}

return v.width
}

const dropdownStyles: ComponentSlotStylesInput<DropdownPropsAndState, DropdownVariables> = {
root: ({ props: p }): ICSSInJSStyle => ({
...(p.inline && {
display: 'inline-flex',
}),
}),

container: ({ props: p, variables: v }): ICSSInJSStyle => ({
display: 'flex',
flexWrap: 'wrap',
outline: 0,
backgroundColor: v.backgroundColor,
position: 'relative',
boxSizing: 'border-box',
borderStyle: 'solid',
borderColor: 'transparent',
outline: 0,
width: getWidth(p, v),
borderWidth: v.borderWidth,
borderRadius: v.borderRadius,
color: v.color,
width: p.fluid ? '100%' : v.width,
position: 'relative',
backgroundColor: v.backgroundColor,
...(p.focused && { borderBottomColor: v.borderColorFocus }),
...(p.inline && transparentColorStyleObj),
}),

selectedItems: ({ props: p, variables: v }): ICSSInJSStyle => ({
Expand All @@ -32,19 +67,14 @@ const dropdownStyles: ComponentSlotStylesInput<DropdownProps & DropdownState, Dr
}),

triggerButton: ({ props: p, variables: v }): ICSSInJSStyle => {
const transparentColorStyle = {
backgroundColor: 'transparent',
borderColor: 'transparent',
}
return {
boxShadow: 'none',
margin: '0',
justifyContent: 'left',
padding: v.comboboxPaddingButton,
height: pxToRem(30),
...transparentColorStyle,
...(p.multiple && { minWidth: 0, flex: 1 }),
':hover': transparentColorStyle,
...transparentColorStyleObj,
':focus': {
...transparentColorStyle,
':after': {
Expand All @@ -54,7 +84,11 @@ const dropdownStyles: ComponentSlotStylesInput<DropdownProps & DropdownState, Dr
},
':active': transparentColorStyle,
},
':active': transparentColorStyle,
...(p.inline && {
paddingLeft: 0,
paddingRight: 0,
width: 'initial',
}),
}
},

Expand All @@ -65,7 +99,7 @@ const dropdownStyles: ComponentSlotStylesInput<DropdownProps & DropdownState, Dr
zIndex: 1000,
maxHeight: v.listMaxHeight,
overflowY: 'auto',
width: p.fluid ? '100%' : v.width,
width: getWidth(p, v),
top: 'calc(100% + 2px)', // leave room for container + its border
background: v.listBackgroundColor,
...(p.isOpen && {
Expand Down