0
0
mirror of https://github.com/naturalcrit/homebrewery.git synced 2026-01-23 20:53:05 +00:00
Files
homebrewery/shared/naturalcrit/codeEditor/helpers/widget-elements/hints/hints.jsx

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;