+ );
+ }
+
+ static propTypes = {
+ inputRef: PropTypes.object,
+ onSearch: PropTypes.func,
+ timeout: PropTypes.number,
+ value: PropTypes.string,
+ };
+
+ static defaultProps = {
+ onSearch: () => {},
+ timeout: 300,
+ value: '',
+ };
+}
+
+module.exports = Search;
diff --git a/chrome/content/zotero/components/tag-selector.jsx b/chrome/content/zotero/components/tag-selector.jsx
index 4d2bd11f74..bf415fa671 100644
--- a/chrome/content/zotero/components/tag-selector.jsx
+++ b/chrome/content/zotero/components/tag-selector.jsx
@@ -6,6 +6,7 @@ const TagList = require('./tag-selector/tag-list');
const Input = require('./form/input');
const { Button } = require('./button');
const { IconTagSelectorMenu } = require('./icons');
+const Search = require('./search');
class TagSelector extends React.Component {
render() {
@@ -13,13 +14,11 @@ class TagSelector extends React.Component {
- this.focusTextbox = ref && ref.focus}
+
}
@@ -46,8 +45,8 @@ TagSelector.propTypes = {
onDragExit: PropTypes.func,
onDrop: PropTypes.func
}),
+ searchBoxRef: PropTypes.object,
searchString: PropTypes.string,
- shouldFocus: PropTypes.bool,
onSelect: PropTypes.func,
onTagContext: PropTypes.func,
onSearch: PropTypes.func,
@@ -58,7 +57,6 @@ TagSelector.propTypes = {
TagSelector.defaultProps = {
tags: [],
searchString: '',
- shouldFocus: false,
onSelect: () => Promise.resolve(),
onTagContext: () => Promise.resolve(),
onSearch: () => Promise.resolve(),
diff --git a/chrome/content/zotero/containers/tagSelector.jsx b/chrome/content/zotero/containers/tagSelector.jsx
index 3987a3760e..8ca27ef848 100644
--- a/chrome/content/zotero/containers/tagSelector.jsx
+++ b/chrome/content/zotero/containers/tagSelector.jsx
@@ -29,6 +29,11 @@ Zotero.TagSelector = class TagSelectorContainer extends React.Component {
this.displayAllTags = Zotero.Prefs.get('tagSelector.displayAllTags');
this.selectedTags = new Set();
this.state = defaults;
+ this.searchBoxRef = React.createRef();
+ }
+
+ focusTextbox() {
+ this.searchBoxRef.focus();
}
// Update trigger #1 (triggered by ZoteroPane)
@@ -177,9 +182,8 @@ Zotero.TagSelector = class TagSelectorContainer extends React.Component {
});
return this.focusTextbox = ref && ref.focusTextbox}
+ searchBoxRef={this.searchBoxRef}
searchString={this.state.searchString}
- shouldFocus={this.state.shouldFocus}
dragObserver={this.dragObserver}
onSelect={this.state.viewOnly ? () => {} : this.handleTagSelected}
onTagContext={this.handleTagContext}
@@ -226,9 +230,9 @@ Zotero.TagSelector = class TagSelectorContainer extends React.Component {
}
}
- handleSearch = Zotero.Utilities.debounce((searchString) => {
+ handleSearch = (searchString) => {
this.setState({searchString});
- })
+ }
dragObserver = {
onDragOver: function(event) {
diff --git a/scss/_zotero-react-client.scss b/scss/_zotero-react-client.scss
index 49a4c53d1a..2664659a91 100644
--- a/scss/_zotero-react-client.scss
+++ b/scss/_zotero-react-client.scss
@@ -20,6 +20,7 @@
// Components
// --------------------------------------------------
-@import "components/tag-selector";
@import "components/button";
@import "components/icons";
+@import "components/search";
+@import "components/tag-selector";
diff --git a/scss/components/_search.scss b/scss/components/_search.scss
new file mode 100644
index 0000000000..e53f618027
--- /dev/null
+++ b/scss/components/_search.scss
@@ -0,0 +1,21 @@
+.search {
+ position: relative;
+}
+
+.search input {
+ -moz-appearance: searchfield;
+ flex: 1 0;
+ min-width: 40px;
+ height: 24px;
+ padding-left: 4px;
+}
+
+.search .search-cancel-button {
+ background-image: url(chrome://global/skin/icons/searchfield-cancel.svg);
+ position: absolute;
+ width: 14px;
+ height: 14px;
+ top: 6px;
+ right: 6px;
+ cursor: default;
+}
\ No newline at end of file
diff --git a/scss/components/_tag-selector.scss b/scss/components/_tag-selector.scss
index 29d371e0d4..9009cf3961 100644
--- a/scss/components/_tag-selector.scss
+++ b/scss/components/_tag-selector.scss
@@ -24,6 +24,13 @@
height: 100%;
}
+.tag-selector-list {
+ list-style: none;
+ display: inline-block;
+ margin: 0;
+ padding: 0;
+}
+
.tag-selector-filter-container {
height: auto;
flex: 0 0 1em;
@@ -32,16 +39,9 @@
padding: 0.125em 0 0.125em 0.5em;
}
-.tag-selector-list {
- list-style: none;
- display: inline-block;
- margin: 0;
- padding: 0;
-}
-
-.tag-selector-filter {
+.tag-selector-filter-container .search {
+ display: flex;
flex: 1 0;
- min-width: 40px;
}
.tag-selector-actions {