From fb6fd4762b041ab7f1220a354c2a586bc30883de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A1ssio=20Zen?= Date: Wed, 6 Jul 2016 18:10:13 -0300 Subject: [PATCH] command scope interface --- src/containers/FindBar.css | 41 +++++++++---- src/containers/FindBar.js | 114 ++++++++++++++++++++++++------------- 2 files changed, 102 insertions(+), 53 deletions(-) diff --git a/src/containers/FindBar.css b/src/containers/FindBar.css index f4d15aff..735e6e59 100644 --- a/src/containers/FindBar.css +++ b/src/containers/FindBar.css @@ -1,18 +1,36 @@ .root { width: 350px; - -} - -.input { - background: none transparent; - border: 0 none; - font-size: inherit; - outline: none; - width: 100%; } .inputArea { - border: solid 1px #000; + display: table; + width: 100%; + border: 1px solid #ddd; + border-radius: 3px; + box-shadow: inset 0 1px 2px rgba(0,0,0,0.075); +} + +.inputScope { + display: table-cell; + width: 1%; + padding-right: 6px; + padding-left: 8px; + color: #767676; + white-space: nowrap; + vertical-align: middle; + border-right: 1px solid #eee; + border-top-left-radius: 2px; + border-bottom-left-radius: 2px; +} + +.inputField { + display: table-cell; + width: 99%; + background: none transparent; + border: 0 none; + box-shadow: none; + outline: none; + font-size: inherit; } .menu { @@ -20,9 +38,8 @@ box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1); background: rgba(255, 255, 255, 0.9); padding: 2px 0; - overflow: auto; width: 350px; - height: 100px; + height: 100%; } .command { diff --git a/src/containers/FindBar.js b/src/containers/FindBar.js index 16fe8d40..728152c3 100644 --- a/src/containers/FindBar.js +++ b/src/containers/FindBar.js @@ -9,11 +9,15 @@ class FindBar extends Component { super(props); this._compiledCommands = {}; this.state = { - value: this.props.initialValue, + value: '', + placeholder: '', + activeScope: null, isOpen: false, highlightedIndex: 0, }; + this._getSuggestions = _.memoize(this._getSuggestions, (value, activeScope) => value + activeScope); + this.compileCommand = this.compileCommand.bind(this); this.matchCommand = this.matchCommand.bind(this); this.handleChange = this.handleChange.bind(this); @@ -21,7 +25,7 @@ class FindBar extends Component { this.handleInputBlur = this.handleInputBlur.bind(this); this.handleInputFocus = this.handleInputFocus.bind(this); this.handleInputClick = this.handleInputClick.bind(this); - this.getSuggestions = _.memoize(this.getSuggestions); + this.getSuggestions = this.getSuggestions.bind(this); this.highlightCommandFromMouse = this.highlightCommandFromMouse.bind(this); this.selectCommandFromMouse = this.selectCommandFromMouse.bind(this); this.setIgnoreBlur = this.setIgnoreBlur.bind(this); @@ -66,36 +70,57 @@ class FindBar extends Component { }); } - matchCommand(string) { + matchCommand() { + const string = this.state.activeScope ? this.state.activeScope + this.state.value : this.state.value; let match; - const command = this.compiledCommands.find(command => { + const command = this._compiledCommands.find(command => { match = string.match(RegExp(`^${command.regexp}`, 'i')); return match; }); - if (command === null) return null; + const param = match[1] && match[1].trim(); + if (!command) { + return null; + } else if (command && !param) { + this.setState({ + value: '', + activeScope: command.token, + placeholder: command.param.display + }); + } + console.log({ + command, + param + }) return { command, - param: match[1] && match[1].trim() + param }; } handleChange(event) { this.setState({ value: event.target.value, - }, () => { - this.props.onChange(event, this.state.value); }); } handleKeyDown(event) { + let highlightedIndex, index; switch (event.key) { + case 'Backspace': + if (this.state.value.length === 0 && this.state.activeScope) { + this.setState({ + activeScope: null, + placeholder: '' + }); + } + break; case 'ArrowDown': event.preventDefault(); - let { highlightedIndex } = this.state; - let index = ( - highlightedIndex === this.getSuggestions(this.state.value, this._compiledCommands).length - 1 || + highlightedIndex = this.state.highlightedIndex; + index = ( + highlightedIndex === this.getSuggestions().length - 1 || this.state.isOpen === false ) ? 0 : highlightedIndex + 1; this.setState({ @@ -105,10 +130,10 @@ class FindBar extends Component { break; case 'ArrowUp': event.preventDefault(); - let { highlightedIndex } = this.state; - let index = ( + highlightedIndex = this.state.highlightedIndex; + index = ( highlightedIndex === 0 - ) ? this.getSuggestions(this.state.value, this._compiledCommands).length - 1 : highlightedIndex - 1; + ) ? this.getSuggestions().length - 1 : highlightedIndex - 1; this.setState({ highlightedIndex: index, isOpen: true, @@ -116,18 +141,21 @@ class FindBar extends Component { break; case 'Enter': if (this.state.isOpen) { - const command = this.getSuggestions(this.state.value, this._compiledCommands)[this.state.highlightedIndex]; - this.setState({ - value: command.token, + const command = this.getSuggestions()[this.state.highlightedIndex]; + const newState = { isOpen: false, highlightedIndex: 0 - }, () => { - this.refs.input.focus(); - this.refs.input.setSelectionRange( + }; + if (command) { + newState.value = command.token; + } + this.setState(newState, () => { + this._input.focus(); + this._input.setSelectionRange( this.state.value.length, this.state.value.length ); - this.props.onSelect(this.state.value, command); + this.matchCommand(); }); } break; @@ -163,15 +191,19 @@ class FindBar extends Component { this.setState({ isOpen: true }); } - getSuggestions(value, commands) { + _getSuggestions(value, scope, commands) { + if (scope) return []; // TODO: Prepare for multiple params & search suggestions const results = fuzzy.filter(value, commands, { //pre: '', //post: '', extract: el => el.token }); - return results.map(result => result.original); + return results.slice(0, 5).map(result => result.original); } + getSuggestions() { + return this._getSuggestions(this.state.value, this.state.activeScope, this._compiledCommands); + } highlightCommandFromMouse(index) { this.setState({ highlightedIndex: index }); @@ -183,8 +215,8 @@ class FindBar extends Component { isOpen: false, highlightedIndex: 0 }, () => { - this.props.onSelect(this.state.value, command); - this.refs.input.focus(); + this.matchCommand(); + this._input.focus(); this.setIgnoreBlur(false); }); } @@ -194,7 +226,7 @@ class FindBar extends Component { } renderMenu() { - const commands = this.getSuggestions(this.state.value, this._compiledCommands).map((command, index) => { + const commands = this.getSuggestions().map((command, index) => { return (
; + return commands.length > 0 ?
: null; + } + + renderActiveScope() { + return
{this.state.activeScope}
; } render() { + const menu = this.state.isOpen && this.renderMenu(); + const scope = this.state.activeScope && this.renderActiveScope(); return (
-
+
- {this.state.isOpen && this.renderMenu()} + + {menu}
); } } FindBar.propTypes = { - commands: PropTypes.array, - initialValue: PropTypes.any, - onChange: PropTypes.func, - onSelect: PropTypes.func, + commands: PropTypes.array.isRequired }; -FindBar.defaultProps = { - initialValue: '', - onChange() {}, - onSelect(value, command) {} -}; module.exports = FindBar;