Skip to content

Commit

Permalink
Merge e00fc5d into c087fdc
Browse files Browse the repository at this point in the history
  • Loading branch information
visusnet committed Jul 25, 2018
2 parents c087fdc + e00fc5d commit e9fc640
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 4 deletions.
54 changes: 50 additions & 4 deletions src/Typeahead.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,15 +76,20 @@ type State = {
isOpen: boolean,
typedLabel: string,
value: ?any,
props: ?Props
props: ?Props,
menuOpenDirection: 'down' | 'up'
};

const MENU_OPEN_DIRECTION_DOWN = 'down';
const MENU_OPEN_DIRECTION_UP = 'up';

const INITIAL_STATE: State = {
highlightedIndex: NOTHING_HIGHLIGHTED,
isOpen: false,
typedLabel: '',
value: undefined,
props: undefined
props: undefined,
menuOpenDirection: MENU_OPEN_DIRECTION_DOWN
};

export default class Typeahead extends PureComponent<Props, State> {
Expand Down Expand Up @@ -447,12 +452,53 @@ export default class Typeahead extends PureComponent<Props, State> {
}
};

_handleScroll = () => {
this._updateMenuOpenDirection();
};

_handleResize = () => {
this._updateMenuOpenDirection();
};

_updateMenuOpenDirection = () => {
const container = this.elementRefs['container'];
const rows = this._generateRows(
this._getFilteredOptions(),
this.props.groups,
this.props,
this._isUnknownValue()
);

const totalRowsHeight = this._calculateTotalRowHeights(rows, this.props);
const spacingThreshold = DEFAULT_GROUP_PADDING + DEFAULT_OPTION_HEIGHT;
const listHeight = this.props.calculateListHeight(rows, totalRowsHeight) + spacingThreshold;

const menuTop = container.getBoundingClientRect().top;
const menuOpenDirection = window.innerHeight < menuTop + listHeight
? MENU_OPEN_DIRECTION_UP
: MENU_OPEN_DIRECTION_DOWN;

if (this.state.menuOpenDirection !== menuOpenDirection) {
this.setState({
menuOpenDirection
});
}
};

componentDidMount(): void {
const {autoSelectSingleOption, options} = this.props;
if (autoSelectSingleOption && options.length === 1) {
const valueOfSingleOption = options[0].value;
this._fireOnChange(valueOfSingleOption);
}

window.addEventListener('scroll', this._handleScroll);
window.addEventListener('resize', this._handleResize);
}

componentWillUnmount() {
window.removeEventListener('scroll', this._handleScroll);
window.removeEventListener('resize', this._handleResize);
}

componentDidUpdate(prevProps: Props): void {
Expand Down Expand Up @@ -616,9 +662,9 @@ export default class Typeahead extends PureComponent<Props, State> {
render(): Node {
const idProp = this.props.id ? {id: this.props.id} : {};
const tabIndexProp = this.props.tabIndex ? {tabIndex: this.props.tabIndex} : {};
const className = this.props.className;
const className = `${this.props.className} ${this.props.className}--${this.state.menuOpenDirection}`;
return (
<div className={className}>
<div className={className} ref={element => this.elementRefs['container'] = element}>
<input
{...idProp}
{...tabIndexProp}
Expand Down
48 changes: 48 additions & 0 deletions src/Typeahead.spec.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -1011,6 +1011,38 @@ describe('Typeahead should', () => {
}
});

it('change menu open direction on resize events', () => {
const wrapper = mount(<Typeahead fieldName="fieldName" options={options}/>);
expect(wrapper.state('menuOpenDirection')).toEqual('down');
resizeTo(1024, 1);
expect(wrapper.state('menuOpenDirection')).toEqual('up');
resizeTo(1024, 768);
expect(wrapper.state('menuOpenDirection')).toEqual('down');
});

it('change menu open direction on scroll events', () => {
mount(<Typeahead fieldName="fieldName" options={options}/>);
scrollTo(768);
// Unfortunately, there is no way in JSDOM to update the calculated values of getBoundingClientRect().
// Therefore, there is no assertion that would work here.
});

it('not react to resize events after unmount', () => {
const wrapper = mount(<Typeahead fieldName="fieldName" options={options}/>);
wrapper.unmount();
resizeTo(1024, 1);
wrapper.mount();
expect(wrapper.state('menuOpenDirection')).toEqual('down');
});

it('not react to scroll events after unmount', () => {
const wrapper = mount(<Typeahead fieldName="fieldName" options={options}/>);
wrapper.unmount();
scrollTo(768);
wrapper.mount();
expect(wrapper.state('menuOpenDirection')).toEqual('down');
});

function simulateKeys(wrapper, text) {
const input = wrapper.find('input');
for (let i = 0; i < text.length; i++) {
Expand All @@ -1030,4 +1062,20 @@ describe('Typeahead should', () => {
});
}
}

function resizeTo(width, height) {
const resizeEvent = document.createEvent('Event');
resizeEvent.initEvent('resize', true, true);

window.innerWidth = width || window.innerWidth;
window.innerHeight = height || window.innerHeight;
window.dispatchEvent(resizeEvent);
}

function scrollTo(top) {
const resizeEvent = document.createEvent('Event');
resizeEvent.initEvent('scroll', true, true);
window.top = top;
window.dispatchEvent(resizeEvent);
}
});

0 comments on commit e9fc640

Please sign in to comment.