Skip to content
This repository was archived by the owner on Mar 4, 2020. It is now read-only.
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 @@ -27,6 +27,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
### Features
- Allow `useRef` hook used for storing debugging data to be defined in any order with other hooks in functional components @layershifter, @mnajdova ([#2236](https://github.com/microsoft/fluent-ui-react/pull/2236))
- Add `useStyles()` hook to use theming capabilities in custom components @layershifter, @mnajdova ([#2217](https://github.com/microsoft/fluent-ui-react/pull/2217))
- Add optional wrapper function to `List` which can be used to inject custom scrollbars to `Dropdown` @jurokapsiar ([#2092](https://github.com/microsoft/fluent-ui-react/pull/2092))

<!--------------------------------[ v0.43.0 ]------------------------------- -->
## [v0.43.0](https://github.com/microsoft/fluent-ui-react/tree/v0.43.0) (2020-01-08)
Expand Down
27 changes: 26 additions & 1 deletion docs/src/prototypes/customScrollbar/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as React from 'react'
import * as _ from 'lodash'
import Scrollbars from 'react-custom-scrollbars'
import { Text, Menu, List, Button, Popup, Dialog } from '@fluentui/react'
import { Text, Menu, List, Button, Popup, Dialog, Dropdown } from '@fluentui/react'
import { PrototypeSection, ComponentPrototype } from '../Prototypes'

const ScrollbarMenuPrototype = () => {
Expand Down Expand Up @@ -71,6 +71,28 @@ const ScrollbarListPrototype = () => {
)
}

const ScrollbarDropdownPrototype = () => {
const items = _.range(50).map((i: number) => ({
header: `Header ${i}`,
content: `Content ${i}`,
key: `item-${i}`,
}))

return (
<div>
<Dropdown
items={items}
list={{ wrap: children => <Scrollbars style={{ height: '20rem' }}>{children}</Scrollbars> }}
/>
<Dropdown
search
items={items}
list={{ wrap: children => <Scrollbars style={{ height: '20rem' }}>{children}</Scrollbars> }}
/>
</div>
)
}

const CustomScrollbarPrototypes: React.FC = () => {
return (
<PrototypeSection title="Custom Scrollbar">
Expand All @@ -93,6 +115,9 @@ const CustomScrollbarPrototypes: React.FC = () => {
<ComponentPrototype title="List" description="Scrollbar can be integrated in selectable List">
<ScrollbarListPrototype />
</ComponentPrototype>
<ComponentPrototype title="Dropdown" description="Scrollbar can be integrated in Dropdown">
<ScrollbarDropdownPrototype />
</ComponentPrototype>
</PrototypeSection>
)
}
Expand Down
40 changes: 28 additions & 12 deletions packages/react/src/components/Dropdown/Dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import {
UIComponentProps,
isFromKeyboard,
} from '../../utils'
import List from '../List/List'
import List, { ListProps } from '../List/List'
import DropdownItem, { DropdownItemProps } from './DropdownItem'
import DropdownSelectedItem, { DropdownSelectedItemProps } from './DropdownSelectedItem'
import DropdownSearchInput, { DropdownSearchInputProps } from './DropdownSearchInput'
Expand Down Expand Up @@ -136,6 +136,9 @@ export interface DropdownProps
/** Used when comparing two items in multiple selection. Default comparison is by the header prop. */
itemToValue?: (item: ShorthandValue<DropdownItemProps>) => any

/** A slot for dropdown list. */
list?: ShorthandValue<ListProps>

/** A dropdown can show that it is currently loading data. */
loading?: boolean

Expand Down Expand Up @@ -280,6 +283,7 @@ class Dropdown extends AutoControlledComponent<WithAsProp<DropdownProps>, Dropdo
items: customPropTypes.collectionShorthand,
itemToString: PropTypes.func,
itemToValue: PropTypes.func,
list: customPropTypes.itemShorthand,
loading: PropTypes.bool,
loadingMessage: customPropTypes.itemShorthand,
moveFocusOnTab: PropTypes.bool,
Expand Down Expand Up @@ -327,6 +331,7 @@ class Dropdown extends AutoControlledComponent<WithAsProp<DropdownProps>, Dropdo
// targets DropdownItem shorthand objects
return (item as any).header || String(item)
},
list: {},
position: 'below',
toggleIndicator: {},
triggerButton: {},
Expand Down Expand Up @@ -653,7 +658,7 @@ class Dropdown extends AutoControlledComponent<WithAsProp<DropdownProps>, Dropdo
getInputProps: (options?: GetInputPropsOptions) => any,
rtl: boolean,
) {
const { align, offset, position, search, unstable_pinned } = this.props
const { align, offset, position, search, unstable_pinned, list } = this.props
const { open } = this.state
const items = open ? this.renderItems(styles, variables, getItemProps, highlightedIndex) : []
const { innerRef, ...accessibilityMenuProps } = getMenuProps(
Expand Down Expand Up @@ -695,16 +700,27 @@ class Dropdown extends AutoControlledComponent<WithAsProp<DropdownProps>, Dropdo
unstable_pinned={unstable_pinned}
positioningDependencies={[items.length]}
>
<List
className={Dropdown.slotClassNames.itemsList}
{...accessibilityMenuProps}
styles={styles.list}
tabIndex={search ? undefined : -1} // needs to be focused when trigger button is activated.
aria-hidden={!open}
onFocus={this.handleTriggerButtonOrListFocus}
onBlur={this.handleListBlur}
items={items}
/>
{List.create(list, {
defaultProps: () => ({
className: Dropdown.slotClassNames.itemsList,
...accessibilityMenuProps,
styles: styles.list,
items,
tabIndex: search ? undefined : -1, // needs to be focused when trigger button is activated.
'aria-hidden': !open,
}),

overrideProps: (predefinedProps: ListProps) => ({
onFocus: (e: React.SyntheticEvent<HTMLElement>, listProps: IconProps) => {
this.handleTriggerButtonOrListFocus()
_.invoke(predefinedProps, 'onClick', e, listProps)
},
onBlur: (e: React.SyntheticEvent<HTMLElement>, listProps: IconProps) => {
this.handleListBlur(e)
_.invoke(predefinedProps, 'onBlur', e, listProps)
},
}),
})}
</Popper>
</Ref>
)
Expand Down
17 changes: 15 additions & 2 deletions packages/react/src/components/List/List.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@ import {
commonPropTypes,
rtlTextContainer,
applyAccessibilityKeyHandlers,
createShorthandFactory,
ShorthandFactory,
} from '../../utils'
import ListItem, { ListItemProps } from './ListItem'
import {
WithAsProp,
ComponentEventHandler,
withSafeTypeForAs,
ShorthandCollection,
ReactChildren,
} from '../../types'

export interface ListSlotClassNames {
Expand Down Expand Up @@ -62,6 +65,9 @@ export interface ListProps extends UIComponentProps, ChildrenComponentProps {

/** A horizontal list displays elements horizontally. */
horizontal?: boolean

/** An optional wrapper function. */
wrap?: (children: ReactChildren) => React.ReactNode
}

export interface ListState {
Expand Down Expand Up @@ -91,11 +97,13 @@ class List extends AutoControlledComponent<WithAsProp<ListProps>, ListState> {
defaultSelectedIndex: PropTypes.number,
onSelectedIndexChange: PropTypes.func,
horizontal: PropTypes.bool,
wrap: PropTypes.func,
}

static defaultProps = {
as: 'ul',
accessibility: listBehavior as Accessibility,
wrap: children => children,
}

static autoControlledProps = ['selectedIndex']
Expand All @@ -116,6 +124,8 @@ class List extends AutoControlledComponent<WithAsProp<ListProps>, ListState> {
'variables',
]

static create: ShorthandFactory<ListProps>

handleItemOverrides = (predefinedProps: ListItemProps) => {
const { selectable } = this.props

Expand All @@ -135,7 +145,8 @@ class List extends AutoControlledComponent<WithAsProp<ListProps>, ListState> {
}

renderComponent({ ElementType, classes, accessibility, unhandledProps }) {
const { children } = this.props
const { children, items, wrap } = this.props
const hasContent = childrenExist(children) || (items && items.length > 0)

return (
<ElementType
Expand All @@ -145,7 +156,7 @@ class List extends AutoControlledComponent<WithAsProp<ListProps>, ListState> {
{...applyAccessibilityKeyHandlers(accessibility.keyHandlers.root, unhandledProps)}
className={classes.root}
>
{childrenExist(children) ? children : this.renderItems()}
{hasContent && wrap(childrenExist(children) ? children : this.renderItems())}
</ElementType>
)
}
Expand Down Expand Up @@ -176,6 +187,8 @@ class List extends AutoControlledComponent<WithAsProp<ListProps>, ListState> {
}
}

List.create = createShorthandFactory({ Component: List, mappedArrayProp: 'items' })

/**
* A List displays a group of related sequential items.
*
Expand Down