Skip to content

Commit

Permalink
Merge pull request #2824 from JedWatson/v2-redistribute-innerRef
Browse files Browse the repository at this point in the history
V2 redistribute inner ref
  • Loading branch information
JedWatson committed Jul 23, 2018
2 parents 4cd69d5 + 7a3c5c4 commit cc095f8
Show file tree
Hide file tree
Showing 10 changed files with 42 additions and 21 deletions.
10 changes: 10 additions & 0 deletions docs/pages/components/index.js
Expand Up @@ -53,6 +53,16 @@ export default function Components() {
property. These components are given all the current props and state
letting you achieve anything you dream up.
## Inner Ref
Some components also take an innerRef prop that react-select needs in
order to manage internal behaviour. Please assign this to the ref
property of the relevant react-element. For example:
~~~~
const CustomOption = ({ innerRef, innerProps }) => (
<div ref={innerRef} {...innerProps} />)
~~~~
### Inner Props
All functional properties that the component needs are provided in
Expand Down
11 changes: 11 additions & 0 deletions docs/pages/props/index.js
Expand Up @@ -112,6 +112,17 @@ export default function Api() {
letting you achieve anything you dream up. For more information in replacing
components see [the components documentation](/components)
### Inner Ref
Some components are passed an innerRef property to facilitate for internally
managed behaviour within the base select. This should be assigned to the
ref property of the relevant dom element.
i.e.
~~~
const CustomOptionComponent = ({ innerProps, innerRef }) =>
(<div ref={innerRef} {...innerProps} />)
~~~
### Inner Props
All functional properties that the component needs are provided in
Expand Down
8 changes: 6 additions & 2 deletions docs/pages/upgradeGuide/index.js
Expand Up @@ -195,7 +195,7 @@ For example, to render a custom \`Option\` component:
~~~js
components={{
Option: ({ children, innerProps }) => (
<div className="custom-option" {...innerProps}>
<div className="custom-option" ref={innerRef} {...innerProps}>
{children}
</div>
)
Expand All @@ -213,8 +213,12 @@ understand are:
* \`getStyles\` - a function that will return an object containing the styles
for the component. If you have specified custom style modifiers, they will be
executed by this function.
* \`innerRef\` - additional some components need to expose a ref to
the base Select component, to facilitate internally managed behaviour.
We specify this as innerRef to avoid collision with React's reserved \`ref\`
keyword when we spread props.
You don't _have_ to use these props, and are free to implement whatever - but
Aside from innerRef (where applicable), you don't _have_ to use these props, and are free to implement whatever - but
they are intended to help make custom implementations easier to manage.
See the [Components Documentation](/components) for more details and
Expand Down
8 changes: 3 additions & 5 deletions src/Select.js
Expand Up @@ -1537,7 +1537,7 @@ export default class Select extends Component<Props, State> {
// for performance, the menu options in state aren't changed when the
// focused option changes so we calculate additional props based on that
const isFocused = focusedOption === props.data;
props.innerProps.innerRef = isFocused
props.innerRef = isFocused
? this.getFocusedOptionRef
: undefined;

Expand Down Expand Up @@ -1606,9 +1606,7 @@ export default class Select extends Component<Props, State> {
<ScrollBlock isEnabled={menuShouldBlockScroll}>
<MenuList
{...commonProps}
innerProps={{
innerRef: this.getMenuListRef,
}}
innerRef={this.getMenuListRef}
isLoading={isLoading}
maxHeight={maxMenuHeight}
>
Expand Down Expand Up @@ -1706,8 +1704,8 @@ export default class Select extends Component<Props, State> {
{this.renderLiveRegion()}
<Control
{...commonProps}
innerRef={this.getControlRef}
innerProps={{
innerRef: this.getControlRef,
onMouseDown: this.onControlMouseDown,
onTouchEnd: this.onControlTouchEnd,
}}
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/__snapshots__/Async.test.js.snap
Expand Up @@ -148,11 +148,11 @@ exports[`defaults - snapshot 1`] = `
hasValue={false}
innerProps={
Object {
"innerRef": [Function],
"onMouseDown": [Function],
"onTouchEnd": [Function],
}
}
innerRef={[Function]}
isDisabled={false}
isFocused={false}
isMulti={false}
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/__snapshots__/AsyncCreatable.test.js.snap
Expand Up @@ -180,11 +180,11 @@ exports[`defaults - snapshot 1`] = `
hasValue={false}
innerProps={
Object {
"innerRef": [Function],
"onMouseDown": [Function],
"onTouchEnd": [Function],
}
}
innerRef={[Function]}
isDisabled={false}
isFocused={false}
isMulti={false}
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/__snapshots__/Select.test.js.snap
Expand Up @@ -69,11 +69,11 @@ exports[`snapshot - defaults 1`] = `
hasValue={false}
innerProps={
Object {
"innerRef": [Function],
"onMouseDown": [Function],
"onTouchEnd": [Function],
}
}
innerRef={[Function]}
isDisabled={false}
isFocused={false}
isMulti={false}
Expand Down
7 changes: 3 additions & 4 deletions src/components/Control.js
Expand Up @@ -17,10 +17,10 @@ export type ControlProps = CommonProps &
State & {
/** Children to render. */
children: Node,
innerRef: ElementRef<*>,
/** The mouse down event and the innerRef to pass down to the controller element. */
innerProps: {
onMouseDown: (SyntheticMouseEvent<HTMLElement>) => void,
innerRef: ElementRef<*>,
},
};

Expand Down Expand Up @@ -51,8 +51,7 @@ export const css = ({ isDisabled, isFocused }: State) => ({
});

const Control = (props: ControlProps) => {
const { children, cx, getStyles, className, isDisabled, isFocused, innerProps } = props;
const { innerRef, ...rest } = innerProps;
const { children, cx, getStyles, className, isDisabled, isFocused, innerRef, innerProps } = props;
return (
<div
ref={innerRef}
Expand All @@ -61,7 +60,7 @@ const Control = (props: ControlProps) => {
'control--is-disabled': isDisabled,
'control--is-focused': isFocused
}, className)}
{...rest}
{...innerProps}
>
{children}
</div>
Expand Down
5 changes: 2 additions & 3 deletions src/components/Menu.js
Expand Up @@ -319,7 +319,7 @@ export type MenuListProps = {
/** The children to be rendered. */
children: Node,
/** Inner ref to DOM Node */
innerProps: { innerRef: InnerRef },
innerRef: InnerRef,
};
export type MenuListComponentProps = CommonProps &
MenuListProps &
Expand All @@ -333,8 +333,7 @@ export const menuListCSS = ({ maxHeight }: MenuState) => ({
WebkitOverflowScrolling: 'touch',
});
export const MenuList = (props: MenuListComponentProps) => {
const { children, className, cx, getStyles, isMulti, innerProps } = props;
const { innerRef } = innerProps;
const { children, className, cx, getStyles, isMulti, innerRef } = props;
return (
<div
className={cx(
Expand Down
8 changes: 4 additions & 4 deletions src/components/Option.js
Expand Up @@ -15,7 +15,6 @@ type State = {
};
type InnerProps = {
id: string,
innerRef: InnerRef,
key: string,
onClick: MouseEventHandler,
onMouseOver: MouseEventHandler,
Expand All @@ -26,6 +25,8 @@ export type OptionProps = PropsWithStyles &
State & {
/** The children to be rendered. */
children: Node,
/** Inner ref to DOM Node */
innerRef: InnerRef,
/** props passed to the wrapping element for the group. */
innerProps: InnerProps,
/* Text to be displayed representing the option. */
Expand Down Expand Up @@ -57,8 +58,7 @@ export const optionCSS = ({ isDisabled, isFocused, isSelected }: State) => ({
});

const Option = (props: OptionProps) => {
const { children, className, cx, getStyles, isDisabled, isFocused, isSelected, innerProps } = props;
const { innerRef, ...rest } = innerProps;
const { children, className, cx, getStyles, isDisabled, isFocused, isSelected, innerRef, innerProps } = props;
return (
<div
ref={innerRef}
Expand All @@ -72,7 +72,7 @@ const Option = (props: OptionProps) => {
},
className
)}
{...rest}
{...innerProps}
>
{children}
</div>
Expand Down

0 comments on commit cc095f8

Please sign in to comment.