mirror of
https://github.com/naturalcrit/homebrewery.git
synced 2026-01-23 20:53:05 +00:00
113 lines
2.8 KiB
JavaScript
113 lines
2.8 KiB
JavaScript
const React = require('react');
|
|
const ReactDOM = require('react-dom');
|
|
const createClass = require('create-react-class');
|
|
const _ = require('lodash');
|
|
const { NUMBER_PATTERN } = require('../constants');
|
|
|
|
const Hints = createClass({
|
|
hintsRef : React.createRef(),
|
|
activeHintRef : React.createRef(),
|
|
|
|
getDefaultProps : function() {
|
|
return {
|
|
hints : [],
|
|
field : undefined,
|
|
};
|
|
},
|
|
|
|
getInitialState : function() {
|
|
return {
|
|
activeHint : 0
|
|
};
|
|
},
|
|
|
|
componentDidUpdate : function({ hints }) {
|
|
const hintsLength = this.props.hints.length;
|
|
if(hintsLength - 1 < this.state.activeHint && hintsLength !== hints.length) {
|
|
this.setState({
|
|
activeHint : hintsLength === 0 ? 0 : hintsLength - 1
|
|
});
|
|
return;
|
|
}
|
|
|
|
if(this.hintsRef.current && this.activeHintRef.current) {
|
|
const offset = this.activeHintRef.current.offsetTop;
|
|
const scrollTop = this.hintsRef.current.scrollTop;
|
|
if(scrollTop + 50 < offset || scrollTop + 50 > offset) {
|
|
this.hintsRef.current.scrollTo({
|
|
top : offset - 50,
|
|
behavior : 'smooth'
|
|
});
|
|
}
|
|
}
|
|
},
|
|
|
|
componentDidMount : function() {
|
|
},
|
|
|
|
keyDown : function(e) {
|
|
const { code } = e;
|
|
const { activeHint } = this.state;
|
|
const { hints, field } = this.props;
|
|
const match = field.state.value.match(NUMBER_PATTERN);
|
|
if(code === 'ArrowDown') {
|
|
e.preventDefault();
|
|
if(!match) {
|
|
this.setState({
|
|
activeHint : activeHint === hints.length - 1 ? 0 : activeHint + 1
|
|
});
|
|
}
|
|
} else if(code === 'ArrowUp') {
|
|
e.preventDefault();
|
|
if(!match) {
|
|
this.setState({
|
|
activeHint : activeHint === 0 ? hints.length - 1 : activeHint - 1
|
|
});
|
|
}
|
|
} else if(code === 'Enter') {
|
|
e.preventDefault();
|
|
if(!match || !match?.at(3)) {
|
|
field?.hintSelected(hints[activeHint]);
|
|
this.setState({
|
|
activeHint : 0
|
|
});
|
|
}
|
|
}
|
|
},
|
|
|
|
render : function() {
|
|
const { activeHint } = this.state;
|
|
const { hints, field } = this.props;
|
|
if(!field) return null;
|
|
const bounds = field.fieldRef[field.state.id].current?.getBoundingClientRect();
|
|
|
|
const hintElements = hints
|
|
.filter((h)=>h.hint !== field.state.value)
|
|
.map((h, i)=>{
|
|
let className = 'CodeMirror-hint';
|
|
if(activeHint === i) {
|
|
className += ' CodeMirror-hint-active';
|
|
}
|
|
return <li key={i} className={className} onMouseDown={(e)=>field.hintSelected(h, e)}>{h.hint}</li>;
|
|
});
|
|
|
|
let style = {
|
|
display : 'none'
|
|
};
|
|
if(hintElements.length > 1) {
|
|
style = {
|
|
...style,
|
|
display : 'block',
|
|
top : `${bounds.top - 5}px`,
|
|
left : `${bounds.left}px`
|
|
};
|
|
}
|
|
return <React.Fragment>
|
|
<ul role={'listbox'} id={'hints'} aria-expanded={true} className={'CodeMirror-hints default'} style={style} onKeyDown={this.keyDown}>
|
|
{hintElements}
|
|
</ul>
|
|
</React.Fragment>;
|
|
}
|
|
});
|
|
|
|
module.exports = Hints; |