UNPKG

vue-searchbox

Version:

Lightweight searchbox component for Vue

1,487 lines (1,334 loc) 46.6 kB
import VueTypes from 'vue-types'; import { css } from 'emotion'; import styled from '@appbaseio/vue-emotion'; import Searchbase from '@appbaseio/searchbase'; import computeScrollIntoView from 'compute-scroll-into-view'; function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } function _taggedTemplateLiteralLoose(strings, raw) { if (!raw) { raw = strings.slice(0); } strings.raw = raw; return strings; } VueTypes.sensibleDefaults = false; var DataField = VueTypes.shape({ field: VueTypes.string, weight: VueTypes.number }); var types = { app: VueTypes.string.isRequired, url: VueTypes.string.def("https://scalr.api.appbase.io"), credentials: VueTypes.string.isRequired, analytics: VueTypes.bool.def(false), headers: VueTypes.object, dataField: VueTypes.oneOfType([VueTypes.string, VueTypes.arrayOf(VueTypes.oneOfType([VueTypes.string, DataField]))]), nestedField: VueTypes.string, title: VueTypes.string, defaultValue: VueTypes.string, placeholder: VueTypes.string.def("Search"), showIcon: VueTypes.bool.def(true), iconPosition: VueTypes.oneOf(["left", "right"]).def("right"), icon: VueTypes.any, showClear: VueTypes.bool.def(false), clearIcon: VueTypes.any, autosuggest: VueTypes.bool.def(true), strictSelection: VueTypes.bool.def(false), defaultSuggestions: VueTypes.arrayOf(VueTypes.object), debounce: VueTypes.number.def(0), highlight: VueTypes.bool.def(false), highlightField: VueTypes.oneOfType([VueTypes.string, VueTypes.arrayOf(VueTypes.string)]), customHighlight: VueTypes.func, queryFormat: VueTypes.oneOf(["and", "or"]).def("or"), fuzziness: VueTypes.oneOf([0, 1, 2, "AUTO"]), showVoiceSearch: VueTypes.bool.def(false), searchOperators: VueTypes.bool.def(false), render: VueTypes.func, renderError: VueTypes.oneOfType([VueTypes.string, VueTypes.any]), renderNoSuggestion: VueTypes.oneOfType([VueTypes.string, VueTypes.any]), renderAllSuggestions: VueTypes.oneOfType([VueTypes.string, VueTypes.func]), renderMic: VueTypes.func, innerClass: VueTypes.object, style: VueTypes.object, defaultQuery: VueTypes.func, beforeValueChange: VueTypes.func, className: VueTypes.string.def(""), loader: VueTypes.object, autoFocus: VueTypes.bool.def(false), currentURL: VueTypes.string.def(""), searchTerm: VueTypes.string.def("search"), URLParams: VueTypes.bool.def(false), analyticsConfig: VueTypes.shape({ emptyQuery: VueTypes.bool, suggestionAnalytics: VueTypes.bool, userId: VueTypes.string, customEvents: VueTypes.object }).def({}) }; function _templateObject6() { var data = _taggedTemplateLiteralLoose(["\n padding-right: 48px;\n "]); _templateObject6 = function _templateObject6() { return data; }; return data; } function _templateObject5() { var data = _taggedTemplateLiteralLoose(["\n padding-right: 32px;\n "]); _templateObject5 = function _templateObject5() { return data; }; return data; } function _templateObject4() { var data = _taggedTemplateLiteralLoose(["\n padding-right: 32px;\n "]); _templateObject4 = function _templateObject4() { return data; }; return data; } function _templateObject3() { var data = _taggedTemplateLiteralLoose(["\n padding-left: 32px;\n "]); _templateObject3 = function _templateObject3() { return data; }; return data; } function _templateObject2() { var data = _taggedTemplateLiteralLoose(["\n ", "\n\n ", ";\n\n ", ";\n\n ", ";\n\n ", ";\n"]); _templateObject2 = function _templateObject2() { return data; }; return data; } function _templateObject() { var data = _taggedTemplateLiteralLoose(["\n width: 100%;\n height: 42px;\n padding: 8px 12px;\n border: 1px solid #ccc;\n background-color: #fafafa;\n font-size: 0.9rem;\n outline: none;\n box-sizing: border-box;\n\n &:focus {\n background-color: #fff;\n }\n"]); _templateObject = function _templateObject() { return data; }; return data; } var input = css(_templateObject()); var Input = styled('input')(_templateObject2(), input, function (props) { return props.showIcon && props.iconPosition === "left" && css(_templateObject3()); }, function (props) { return props.showIcon && props.iconPosition === "right" && css(_templateObject4()); }, function (props) { return (// for clear icon props.showClear && css(_templateObject5()) ); }, function (props) { return (// for clear icon with search icon props.showClear && props.showIcon && props.iconPosition === "right" && css(_templateObject6()) ); }); var getClassName = function getClassName(classMap, component) { return classMap && classMap[component] || ""; }; /** * To determine wether an element is a function * @param {any} element */ var equals = function equals(a, b) { if (a === b) return true; if (!a || !b || typeof a !== "object" && typeof b !== "object") return a === b; if (a === null || a === undefined || b === null || b === undefined) return false; if (a.prototype !== b.prototype) return false; var keys = Object.keys(a); if (keys.length !== Object.keys(b).length) return false; return keys.every(function (k) { return equals(a[k], b[k]); }); }; var debounce = function debounce(fn, delay) { var timer = null; return function () { for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } var context = this; timer && clearTimeout(timer); timer = setTimeout(function () { fn.apply(context, args); }, delay); }; }; /** * Scroll node into view if necessary * @param {HTMLElement} node the element that should scroll into view * @param {HTMLElement} rootNode the root element of the component */ // eslint-disable-next-line // for downshift var scrollIntoView = function scrollIntoView(node, rootNode) { if (node === null) { return; } var actions = computeScrollIntoView(node, { boundary: rootNode, block: "nearest", scrollMode: "if-needed" }); actions.forEach(function (_ref) { var el = _ref.el, top = _ref.top, left = _ref.left; el.scrollTop = top; el.scrollLeft = left; }); }; // escapes regex for special characters: \ => \\, $ => \$ function escapeRegExp(string) { return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string } var getURLParameters = function getURLParameters(url) { var keyVal = {}; url.replace(/[?&]+([^=&]+)=([^&]*)/gi, function (m, key, value) { key = decodeURIComponent(key); value = decodeURIComponent(value); keyVal[key] = value; }); return keyVal; }; var isEmpty = function isEmpty(val) { return !(val && val.length && Object.keys(val).length); }; var withClickIds = function withClickIds(results) { if (results === void 0) { results = []; } return results.map(function (result, index) { return _extends({}, result, { _click_id: index }); }); }; var DownShift = { // eslint-disable-next-line props: ["isOpen", "inputValue", "selectedItem", "highlightedIndex", "handleChange", "itemToString", "handleMouseup"], data: function data() { return { isMouseDown: false, internal_isOpen: false, internal_inputValue: "", internal_selectedItem: null, internal_highlightedIndex: null }; }, computed: { mergedState: function mergedState() { var _this = this; return Object.keys(this.$props).reduce(function (state, key) { var _extends2; return _extends({}, state, (_extends2 = {}, _extends2[key] = _this.isControlledProp(key) ? _this.$props[key] : _this["internal_" + key], _extends2)); }, {}); }, internalItemCount: function internalItemCount() { return this.items.length; } }, mounted: function mounted() { window.addEventListener("mousedown", this.handleWindowMousedown); window.addEventListener("mouseup", this.handleWindowMouseup); }, beforeDestroy: function beforeDestroy() { window.removeEventListener("mousedown", this.handleWindowMousedown); window.removeEventListener("mouseup", this.handleWindowMouseup); }, methods: { handleWindowMousedown: function handleWindowMousedown() { this.isMouseDown = true; }, handleWindowMouseup: function handleWindowMouseup(event) { this.isMouseDown = false; if ((event.target === this.$refs.rootNode || !this.$refs.rootNode.contains(event.target)) && this.mergedState.isOpen) { // TODO: handle on outer click here if (!this.isMouseDown) { this.reset(); if (this.$props.handleMouseup) { this.$props.handleMouseup({ isOpen: false }); } } } }, keyDownArrowDown: function keyDownArrowDown(event) { event.preventDefault(); var amount = event.shiftKey ? 5 : 1; if (this.mergedState.isOpen) { this.changeHighlightedIndex(amount); } else { this.setState({ isOpen: true }); this.setHighlightedIndex(); } }, keyDownArrowUp: function keyDownArrowUp(event) { event.preventDefault(); var amount = event.shiftKey ? -5 : -1; if (this.mergedState.isOpen) { this.changeHighlightedIndex(amount); } else { this.setState({ isOpen: true }); this.setHighlightedIndex(); } }, keyDownEnter: function keyDownEnter(event) { if (this.mergedState.isOpen) { event.preventDefault(); this.selectHighlightedItem(); } }, keyDownEscape: function keyDownEscape(event) { event.preventDefault(); this.reset(); }, selectHighlightedItem: function selectHighlightedItem() { return this.selectItemAtIndex(this.mergedState.highlightedIndex); }, selectItemAtIndex: function selectItemAtIndex(itemIndex) { var item = this.items[itemIndex]; if (item == null) { return; } this.selectItem(item); }, selectItem: function selectItem(item) { if (this.$props.handleChange) { this.$props.handleChange(item); } this.setState({ isOpen: false, highlightedIndex: null, selectedItem: item, inputValue: this.isControlledProp("selectedItem") ? "" : item }); }, changeHighlightedIndex: function changeHighlightedIndex(moveAmount) { if (this.internalItemCount < 0) { return; } var highlightedIndex = this.mergedState.highlightedIndex; var baseIndex = highlightedIndex; if (baseIndex === null) { baseIndex = moveAmount > 0 ? -1 : this.internalItemCount + 1; } var newIndex = baseIndex + moveAmount; if (newIndex < 0) { newIndex = this.internalItemCount; } else if (newIndex > this.internalItemCount) { newIndex = 0; } this.setHighlightedIndex(newIndex); }, setHighlightedIndex: function setHighlightedIndex(highlightedIndex) { if (highlightedIndex === void 0) { highlightedIndex = null; } this.setState({ highlightedIndex: highlightedIndex }); var element = document.getElementById("Downshift" + highlightedIndex); scrollIntoView(element, this.rootNode); // Implement scrollIntroView thingy }, reset: function reset() { var selectedItem = this.mergedState.selectedItem; this.setState({ isOpen: false, highlightedIndex: null, inputValue: selectedItem }); }, getItemProps: function getItemProps(_ref) { var index = _ref.index, item = _ref.item; var newIndex = index; if (index === undefined) { if (this.$props.itemToString) { this.items.push(this.$props.itemToString(item)); } else { this.items.push(item); } newIndex = this.items.indexOf(item); } else { this.items[newIndex] = item; } return { id: "Downshift" + newIndex }; }, getItemEvents: function getItemEvents(_ref2) { var index = _ref2.index, item = _ref2.item; var newIndex = index; if (index === undefined) { newIndex = this.items.indexOf(item); } var vm = this; return { mouseenter: function mouseenter() { vm.setHighlightedIndex(newIndex); }, click: function click(event) { event.stopPropagation(); vm.selectItemAtIndex(newIndex); } }; }, getInputProps: function getInputProps(_ref3) { var value = _ref3.value; var inputValue = this.mergedState.inputValue; if (value !== inputValue) { this.setState({ inputValue: value }); } return { value: inputValue }; }, getButtonProps: function getButtonProps(_ref4) { var _this2 = this; var onClick = _ref4.onClick, onKeyDown = _ref4.onKeyDown, onKeyUp = _ref4.onKeyUp, onBlur = _ref4.onBlur; return { click: function click(event) { _this2.setState({ isOpen: true, inputValue: event.target.value }); if (onClick) { onClick(event); } }, keydown: function keydown(event) { if (event.key && _this2["keyDown" + event.key]) { _this2["keyDown" + event.key].call(_this2, event); } if (onKeyDown) { onKeyDown(event); } }, keyup: function keyup(event) { if (onKeyUp) { onKeyUp(event); } }, blur: function blur(event) { if (onBlur) { onBlur(event); } } }; }, getInputEvents: function getInputEvents(_ref5) { var _this3 = this; var onInput = _ref5.onInput, onBlur = _ref5.onBlur, onFocus = _ref5.onFocus, onKeyPress = _ref5.onKeyPress, onKeyDown = _ref5.onKeyDown, onKeyUp = _ref5.onKeyUp; return { input: function input(event) { _this3.setState({ isOpen: true, inputValue: event.target.value }); if (onInput) { onInput(event); } }, focus: function focus(event) { if (onFocus) { onFocus(event); } }, keydown: function keydown(event) { if (event.key && _this3["keyDown" + event.key]) { _this3["keyDown" + event.key].call(_this3, event); } if (onKeyDown) { onKeyDown(event); } }, keypress: function keypress(event) { if (onKeyPress) { onKeyPress(event); } }, keyup: function keyup(event) { if (onKeyUp) { onKeyUp(event); } }, blur: function blur(event) { if (onBlur) { onBlur(event); } // TODO: implement isMouseDown // this.reset() } }; }, getHelpersAndState: function getHelpersAndState() { var getItemProps = this.getItemProps, getItemEvents = this.getItemEvents, getInputProps = this.getInputProps, getInputEvents = this.getInputEvents, getButtonProps = this.getButtonProps; return _extends({ getItemProps: getItemProps, getItemEvents: getItemEvents, getInputProps: getInputProps, getInputEvents: getInputEvents, getButtonProps: getButtonProps }, this.mergedState); }, isControlledProp: function isControlledProp(prop) { return this.$props[prop] !== undefined; }, setState: function setState(stateToSet) { var _this4 = this; // eslint-disable-next-line Object.keys(stateToSet).map(function (key) { // eslint-disable-next-line _this4.isControlledProp(key) ? _this4.$emit(key + "Change", stateToSet[key]) : _this4["internal_" + key] = stateToSet[key]; }); this.$emit("stateChange", this.mergedState); } }, render: function render() { var h = arguments[0]; this.items = []; return h("div", { "ref": "rootNode" }, [this.$scopedSlots["default"] && this.$scopedSlots["default"](_extends({}, this.getHelpersAndState()))]); } }; function _templateObject2$1() { var data = _taggedTemplateLiteralLoose(["\n position: relative;\n .cancel-icon {\n cursor: pointer;\n }\n .no-suggestions {\n border: 1px solid #ccc;\n border-top: 0;\n font-size: 0.9rem;\n padding: 10px;\n }\n"]); _templateObject2$1 = function _templateObject2() { return data; }; return data; } function _templateObject$1() { var data = _taggedTemplateLiteralLoose(["\n display: block;\n width: 100%;\n border: 1px solid #ccc;\n background-color: #fff;\n font-size: 0.9rem;\n z-index: 3;\n position: absolute;\n top: 39px;\n margin: 0;\n padding: 0;\n list-style: none;\n max-height: 260px;\n overflow-y: auto;\n box-sizing: border-box;\n\n &.small {\n top: 30px;\n }\n\n li {\n display: flex;\n justify-content: space-between;\n cursor: pointer;\n padding: 10px;\n user-select: none;\n\n .trim {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n &:hover,\n &:focus {\n background-color: #eee;\n }\n\n .highlight-class {\n font-weight: 600;\n padding: 0;\n background-color: transparent;\n color: inherit;\n }\n }\n"]); _templateObject$1 = function _templateObject() { return data; }; return data; } var suggestions = css(_templateObject$1()); var suggestionsContainer = css(_templateObject2$1()); var SuggestionItem = { props: ["suggestion", "currentValue"], render: function render() { var h = arguments[0]; var _this$$props = this.$props, suggestion = _this$$props.suggestion, currentValue = _this$$props.currentValue; var label = suggestion.label, value = suggestion.value; var modSearchWords = currentValue.split(" ").map(function (word) { return escapeRegExp(word); }); var stringToReplace = modSearchWords.join("|"); if (label) { // label has highest precedence return typeof label === "string" ? h("div", { "attrs": { "className": "trim" }, "domProps": { "innerHTML": label.replace(new RegExp(stringToReplace, "ig"), function (matched) { return "<mark class=\"highlight-class\">" + matched + "</mark>"; }) } }) : label; } return value; } }; function _templateObject$2() { var data = _taggedTemplateLiteralLoose(["\n margin: 0 0 8px;\n font-size: 1rem;\n color: #424242;\n"]); _templateObject$2 = function _templateObject() { return data; }; return data; } var Title = styled("h2")(_templateObject$2()); var CancelSvg = { functional: true, render: function render(h) { return h("svg", { "attrs": { "alt": "Clear", "height": "10", "xmlns": "http://www.w3.org/2000/svg", "viewBox": "0 0 212.982 212.982" }, "class": "cancel-icon" }, [h("title", ["Clear"]), h("path", { "attrs": { "d": "M131.804,106.491l75.936-75.936c6.99-6.99,6.99-18.323,0-25.312c-6.99-6.99-18.322-6.99-25.312,0l-75.937,75.937L30.554,5.242c-6.99-6.99-18.322-6.99-25.312,0c-6.989,6.99-6.989,18.323,0,25.312l75.937,75.936L5.242,182.427c-6.989,6.99-6.989,18.323,0,25.312c6.99,6.99,18.322,6.99,25.312,0l75.937-75.937l75.937,75.937c6.989,6.99,18.322,6.99,25.312,0c6.99-6.99,6.99-18.322,0-25.312L131.804,106.491z" } })]); } }; function _templateObject4$1() { var data = _taggedTemplateLiteralLoose(["\n position: absolute;\n top: 13px;\n cursor: pointer;\n ", ";\n ", ";\n\n svg.search-icon {\n fill: #0b6aff;\n }\n"]); _templateObject4$1 = function _templateObject4() { return data; }; return data; } function _templateObject3$1() { var data = _taggedTemplateLiteralLoose(["\n padding-right: 32px;\n right: 0;\n top: calc(50% - 9px);\n"]); _templateObject3$1 = function _templateObject3() { return data; }; return data; } function _templateObject2$2() { var data = _taggedTemplateLiteralLoose(["\n padding-right: 12px;\n right: 0;\n"]); _templateObject2$2 = function _templateObject2() { return data; }; return data; } function _templateObject$3() { var data = _taggedTemplateLiteralLoose(["\n padding-left: 12px;\n left: 0;\n"]); _templateObject$3 = function _templateObject() { return data; }; return data; } var left = css(_templateObject$3()); var right = css(_templateObject2$2()); var clear = css(_templateObject3$1()); var InputIcon = styled("div")(_templateObject4$1(), function (_ref) { var iconPosition = _ref.iconPosition; if (iconPosition === "left") { return left; } else if (iconPosition === "right") { return right; } return null; }, function (_ref2) { var clearIcon = _ref2.clearIcon; return clearIcon && clear; }); var SearchSvg = { functional: true, render: function render(h) { return h("svg", { "attrs": { "alt": "Search", "height": "14", "xmlns": "http://www.w3.org/2000/svg", "viewBox": "0 0 15 15" }, "class": "search-icon" }, [h("title", ["Search"]), h("path", { "attrs": { "d": "M6.02945,10.20327a4.17382,4.17382,0,1,1,4.17382-4.17382A4.15609,4.15609,0,0,1,6.02945,10.20327Zm9.69195,4.2199L10.8989,9.59979A5.88021,5.88021,0,0,0,12.058,6.02856,6.00467,6.00467,0,1,0,9.59979,10.8989l4.82338,4.82338a.89729.89729,0,0,0,1.29912,0,.89749.89749,0,0,0-.00087-1.29909Z" } })]); } }; function _templateObject3$2() { var data = _taggedTemplateLiteralLoose(["\n right: 22px;\n "]); _templateObject3$2 = function _templateObject3() { return data; }; return data; } function _templateObject2$3() { var data = _taggedTemplateLiteralLoose(["\n height: 40px;\n position: absolute;\n top: calc(50% - 20px);\n cursor: pointer;\n right: 0;\n ", "\n"]); _templateObject2$3 = function _templateObject2() { return data; }; return data; } function _templateObject$4() { var data = _taggedTemplateLiteralLoose(["\n right: 42px;\n"]); _templateObject$4 = function _templateObject() { return data; }; return data; } var right$1 = css(_templateObject$4()); var MicIcon = styled("div")(_templateObject2$3(), function (_ref) { var iconPosition = _ref.iconPosition; if (iconPosition === "right") { return right$1; } return css(_templateObject3$2()); }); var STATUS = { inactive: "INACTIVE", stopped: "STOPPED", active: "ACTIVE", denied: "DENIED" }; var Icon = { props: ["status", "handleMicClick", "className"], render: function render() { var h = arguments[0]; var _this$$props = this.$props, status = _this$$props.status, className = _this$$props.className, handleMicClick = _this$$props.handleMicClick; var url; if (!window.SpeechRecognition) { url = "https://cdn3.iconfinder.com/data/icons/glypho-music-and-sound/64/microphone-off-512.png"; } switch (status) { case STATUS.active: url = "https://media.giphy.com/media/ZZr4lCvpuMP58PXzY1/giphy.gif"; break; case STATUS.stopped: break; case STATUS.denied: url = "https://cdn3.iconfinder.com/data/icons/glypho-music-and-sound/64/microphone-off-512.png"; break; default: url = "https://cdn3.iconfinder.com/data/icons/glypho-music-and-sound/64/microphone-512.png"; } return h("img", { "class": className, "on": { "click": handleMicClick }, "attrs": { "src": url }, "style": { width: "24px", marginTop: "7px" } }); } }; var Mic = { props: ["iconPosition", "handleMicClick", "className", "status"], render: function render() { var h = arguments[0]; var _this$$props2 = this.$props, iconPosition = _this$$props2.iconPosition, className = _this$$props2.className, handleMicClick = _this$$props2.handleMicClick, status = _this$$props2.status; return h(MicIcon, { "attrs": { "iconPosition": iconPosition } }, [h(Icon, { "attrs": { "className": className, "handleMicClick": handleMicClick, "status": status } })]); } }; var SearchIcon = { props: ["showIcon", "icon"], render: function render() { var h = arguments[0]; var _this$$props = this.$props, showIcon = _this$$props.showIcon, icon = _this$$props.icon; if (showIcon) { return icon || h(SearchSvg); } return null; } }; var Icons = { props: ["clearValue", "iconPosition", "showClear", "clearIcon", "currentValue", "handleSearchIconClick", "showIcon", "icon", "enableVoiceSearch", "innerClass", "getMicInstance", "micStatus", "handleMicClick"], render: function render() { var h = arguments[0]; var _this$$props2 = this.$props, clearValue = _this$$props2.clearValue, iconPosition = _this$$props2.iconPosition, showClear = _this$$props2.showClear, clearIcon = _this$$props2.clearIcon, currentValue = _this$$props2.currentValue, handleSearchIconClick = _this$$props2.handleSearchIconClick, showIcon = _this$$props2.showIcon, icon = _this$$props2.icon, enableVoiceSearch = _this$$props2.enableVoiceSearch, innerClass = _this$$props2.innerClass, micStatus = _this$$props2.micStatus, handleMicClick = _this$$props2.handleMicClick; return h("div", [currentValue && showClear && h(InputIcon, { "on": { "click": clearValue }, "attrs": { "iconPosition": "right", "clearIcon": iconPosition === "right" } }, [clearIcon || h(CancelSvg)]), enableVoiceSearch && h(Mic, { "attrs": { "iconPosition": iconPosition, "className": getClassName(innerClass, "mic") || null, "status": micStatus, "handleMicClick": handleMicClick } }), h(InputIcon, { "on": { "click": handleSearchIconClick }, "attrs": { "iconPosition": iconPosition } }, [h(SearchIcon, { "attrs": { "showIcon": showIcon, "icon": icon } })])]); } }; var VueSearchbox = { name: "VueSearchbox", // vue component name props: { app: types.app, url: types.url, credentials: types.credentials, analytics: types.analytics, headers: types.headers, dataField: types.dataField, nestedField: types.nestedField, title: types.title, defaultValue: types.defaultValue, placeholder: types.placeholder, showIcon: types.showIcon, iconPosition: types.iconPosition, icon: types.icon, showClear: types.showClear, clearIcon: types.clearIcon, autosuggest: types.autosuggest, strictSelection: types.strictSelection, defaultSuggestions: types.defaultSuggestions, debounce: types.debounce, highlight: types.highlight, highlightField: types.highlightField, customHighlight: types.customHighlight, queryFormat: types.queryFormat, fuzziness: types.fuzziness, showVoiceSearch: types.showVoiceSearch, searchOperators: types.searchOperators, render: types.render, renderError: types.renderError, renderNoSuggestion: types.renderNoSuggestion, renderAllSuggestions: types.renderAllSuggestions, renderMic: types.renderMic, innerClass: types.innerClass, defaultQuery: types.defaultQuery, beforeValueChange: types.beforeValueChange, className: types.className, loader: types.loader, autoFocus: types.autoFocus, currentURL: types.currentURL, searchTerm: types.searchTerm, URLParams: types.URLParams, analyticsConfig: types.analyticsConfig }, data: function data() { var _this$$props = this.$props, value = _this$$props.value, defaultValue = _this$$props.defaultValue, defaultSuggestions = _this$$props.defaultSuggestions; var currentValue = value || defaultValue || ""; this.state = { currentValue: currentValue, suggestionsList: defaultSuggestions || [], isOpen: false, error: null, loading: false, initError: null, micStatus: undefined }; return this.state; }, created: function created() { this._initSearchBase(); this.triggerSuggestionsQuery = debounce(this.triggerSuggestionsQuery, this.debounce); if (this.URLParams) { this.setValue({ value: this.getSearchTerm(this.currentURL), isOpen: false }); } }, watch: { dataField: function dataField(next, prev) { return this._applySetter(prev, next, "setDataField"); }, headers: function headers(next, prev) { return this._applySetter(prev, next, "setHeaders"); }, fuzziness: function fuzziness(next, prev) { return this._applySetter(prev, next, "setFuzziness"); }, nestedField: function nestedField(next, prev) { return this._applySetter(prev, next, "setNestedField"); }, currentURL: function currentURL(next, prev) { var URLParams = this.$props.URLParams; if (URLParams && prev !== next) { this.setValue({ value: this.getSearchTerm(next), isOpen: false }); } }, analyticsConfig: function analyticsConfig(next, prev) { if (this.analytics && JSON.stringify(next) !== JSON.stringify(prev)) { this.setAnalytics(next); } } }, beforeDestroy: function beforeDestroy() { this.searchBase && this.searchBase.unsubscribeToStateChanges(this.setStateValue); }, methods: { _initSearchBase: function _initSearchBase() { var _this = this; var _this$$props2 = this.$props, app = _this$$props2.app, url = _this$$props2.url, dataField = _this$$props2.dataField, credentials = _this$$props2.credentials, analytics = _this$$props2.analytics, headers = _this$$props2.headers, nestedField = _this$$props2.nestedField, defaultQuery = _this$$props2.defaultQuery, beforeValueChange = _this$$props2.beforeValueChange, queryFormat = _this$$props2.queryFormat, defaultSuggestions = _this$$props2.defaultSuggestions, fuzziness = _this$$props2.fuzziness, searchOperators = _this$$props2.searchOperators; try { var transformQuery = function transformQuery(query) { if (defaultQuery) return defaultQuery(query, _this.$data.currentValue); return Promise.resolve(query); }; this.searchBase = new Searchbase({ index: app, url: url, dataField: dataField, credentials: credentials, analytics: analytics, headers: headers, nestedField: nestedField, transformQuery: transformQuery, beforeValueChange: beforeValueChange, queryFormat: queryFormat, suggestions: defaultSuggestions, fuzziness: fuzziness, searchOperators: searchOperators }); this.searchBase.subscribeToStateChanges(this.setStateValue, ["suggestions"]); this.searchBase.onQueryChange = function () { for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this.$emit.apply(_this, ["queryChange"].concat(args)); }; this.searchBase.onSuggestions = function () { for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { args[_key2] = arguments[_key2]; } _this.$emit.apply(_this, ["suggestions"].concat(args)); }; this.searchBase.onError = function (error) { _this.error = error; _this.$emit("error", error); }; this.searchBase.onSuggestionsRequestStatusChange = function (next) { _this.loading = next === "PENDING"; }; this.searchBase.onMicStatusChange = function (next) { _this.micStatus = next; _this.isOpen = next === "INACTIVE" && !_this.loading; }; this.searchBase.onValueChange = function (nextValue) { _this.currentValue = nextValue; _this.$emit("valueChange", nextValue); }; } catch (e) { this.initError = e; console.error(e); } }, _applySetter: function _applySetter(prev, next, setterFunc) { if (!equals(prev, next)) this.searchBase && this.searchBase[setterFunc](next); }, setAnalytics: function setAnalytics(config) { if (!this.searchBase) return; var emptyQuery = config.emptyQuery, userId = config.userId, customEvents = config.customEvents; var analyticsInstance = this.searchBase.analyticsInstance; emptyQuery ? analyticsInstance.enableEmptyQuery() : analyticsInstance.disableEmptyQuery(); analyticsInstance.setUserID(userId).setCustomEvents(customEvents); }, triggerClickAnalytics: function triggerClickAnalytics(clickPosition, isSuggestion) { if (isSuggestion === void 0) { isSuggestion = true; } var _this$$props3 = this.$props, analytics = _this$$props3.analytics, analyticsConfig = _this$$props3.analyticsConfig; if (!analytics || !analyticsConfig.suggestionAnalytics || !this.searchBase) return; this.searchBase.analyticsInstance.registerClick(clickPosition, isSuggestion); }, setStateValue: function setStateValue(_ref) { var _ref$suggestions = _ref.suggestions, suggestions = _ref$suggestions === void 0 ? {} : _ref$suggestions; this.suggestionsList = withClickIds(suggestions.next && suggestions.next.data) || []; }, getSearchTerm: function getSearchTerm(url) { if (url === void 0) { url = ""; } var searchParams = getURLParameters(url); return searchParams && searchParams[this.searchTerm]; }, onInputChange: function onInputChange(event) { this.setValue({ value: event.target.value, event: event }); }, onSuggestionSelected: function onSuggestionSelected(suggestion) { this.setValue({ value: suggestion && suggestion.value, isOpen: false }); this.triggerClickAnalytics(suggestion && suggestion._click_id); }, setValue: function setValue(_ref2) { var value = _ref2.value, _ref2$isOpen = _ref2.isOpen, isOpen = _ref2$isOpen === void 0 ? true : _ref2$isOpen; var _this$$props4 = this.$props, debounce = _this$$props4.debounce, searchTerm = _this$$props4.searchTerm, URLParams = _this$$props4.URLParams; this.isOpen = isOpen; if (debounce > 0) this.searchBase.setValue(value, { triggerQuery: false }); this.triggerSuggestionsQuery(value); if (URLParams) { var _ref3; window.history.replaceState(!isEmpty(value) ? (_ref3 = {}, _ref3[searchTerm] = value, _ref3) : null, null, !isEmpty(value) ? "?" + searchTerm + "=" + value : window.location.origin); } }, triggerSuggestionsQuery: function triggerSuggestionsQuery(value) { this.searchBase && this.searchBase.setValue(value || "", { triggerSuggestionsQuery: true }); }, handleFocus: function handleFocus(event) { this.isOpen = true; this.$emit("focus", event); }, handleStateChange: function handleStateChange(changes) { var isOpen = changes.isOpen; this.isOpen = isOpen; }, handleKeyDown: function handleKeyDown(event, highlightedIndex) { // if a suggestion was selected, delegate the handling // to suggestion handler if (event.key === "Enter" && highlightedIndex === null) this.setValue({ value: event.target.value, isOpen: false }); this.$emit("keyDown", event); }, handleMicClick: function handleMicClick() { this.searchBase && this.searchBase.onMicClick(null, { triggerSuggestionsQuery: true }); }, renderIcons: function renderIcons() { var h = this.$createElement; var _this$$props5 = this.$props, iconPosition = _this$$props5.iconPosition, showClear = _this$$props5.showClear, clearIcon = _this$$props5.clearIcon, innerClass = _this$$props5.innerClass, showVoiceSearch = _this$$props5.showVoiceSearch, icon = _this$$props5.icon, showIcon = _this$$props5.showIcon; var _this$$data = this.$data, currentValue = _this$$data.currentValue, micStatus = _this$$data.micStatus; return h(Icons, { "attrs": { "clearValue": this.clearValue, "iconPosition": iconPosition, "showClear": showClear, "clearIcon": clearIcon, "currentValue": currentValue, "handleSearchIconClick": this.handleSearchIconClick, "icon": icon, "showIcon": showIcon, "innerClass": innerClass, "enableVoiceSearch": showVoiceSearch, "micStatus": micStatus, "handleMicClick": this.handleMicClick } }); }, renderNoSuggestionComponent: function renderNoSuggestionComponent() { var h = this.$createElement; var _this$$props6 = this.$props, innerClass = _this$$props6.innerClass, renderError = _this$$props6.renderError; var _this$$data2 = this.$data, loading = _this$$data2.loading, error = _this$$data2.error, isOpen = _this$$data2.isOpen, currentValue = _this$$data2.currentValue, suggestionsList = _this$$data2.suggestionsList; var renderNoSuggestion = this.$scopedSlots.renderNoSuggestion || this.$props.renderNoSuggestion; if (renderNoSuggestion && isOpen && !suggestionsList.length && !loading && currentValue && !(renderError && error)) { return h("div", { "class": "no-suggestions " + getClassName(innerClass, "noSuggestion") }, [typeof renderNoSuggestion === "function" ? renderNoSuggestion(currentValue) : renderNoSuggestion]); } return null; }, renderErrorComponent: function renderErrorComponent() { var h = this.$createElement; var innerClass = this.$props.innerClass; var renderError = this.$scopedSlots.renderError || this.$props.renderError; var _this$$data3 = this.$data, error = _this$$data3.error, loading = _this$$data3.loading, currentValue = _this$$data3.currentValue; if (error && renderError && currentValue && !loading) { return h("div", { "class": getClassName(innerClass, "error") }, [typeof renderError === "function" ? renderError(error) : renderError]); } return null; }, clearValue: function clearValue() { this.setValue({ value: "", isOpen: false }); }, handleSearchIconClick: function handleSearchIconClick() { var currentValue = this.$data.currentValue; if (currentValue.trim()) { this.setValue({ value: currentValue, isOpen: false }); } }, getBackgroundColor: function getBackgroundColor(highlightedIndex, index) { return highlightedIndex === index ? "#eee" : "#fff"; } }, render: function render() { var _this2 = this; var h = arguments[0]; var _this$$props7 = this.$props, className = _this$$props7.className, innerClass = _this$$props7.innerClass, showIcon = _this$$props7.showIcon, showClear = _this$$props7.showClear, iconPosition = _this$$props7.iconPosition, title = _this$$props7.title, defaultSuggestions = _this$$props7.defaultSuggestions, autosuggest = _this$$props7.autosuggest, placeholder = _this$$props7.placeholder, autoFocus = _this$$props7.autoFocus, innerRef = _this$$props7.innerRef, renderError = _this$$props7.renderError; var _this$$data4 = this.$data, currentValue = _this$$data4.currentValue, isOpen = _this$$data4.isOpen, suggestionsList = _this$$data4.suggestionsList, initError = _this$$data4.initError; if (initError) { if (renderError) return typeof renderError === "function" ? renderError(initError) : renderError; return h("div", ["Error initializing SearchBase. Please try again."]); } var renderAllSuggestions = this.$scopedSlots.renderAllSuggestions || this.$props.renderAllSuggestions; return h("div", { "class": className }, [title && h(Title, { "class": getClassName(innerClass, "title") || "" }, [title]), defaultSuggestions || autosuggest ? h(DownShift, { "attrs": { "id": "searchbox-downshift", "handleChange": this.onSuggestionSelected, "handleMouseup": this.handleStateChange, "isOpen": isOpen }, "scopedSlots": { "default": function _default(_ref4) { var getInputEvents = _ref4.getInputEvents, getInputProps = _ref4.getInputProps, getItemProps = _ref4.getItemProps, getItemEvents = _ref4.getItemEvents, isOpen = _ref4.isOpen, highlightedIndex = _ref4.highlightedIndex; return h("div", { "class": suggestionsContainer }, [h(Input, { "attrs": { "id": "search-box", "showIcon": showIcon, "showClear": showClear, "iconPosition": iconPosition }, "class": getClassName(innerClass, "input"), "on": _extends({}, getInputEvents({ onInput: _this2.onInputChange, onBlur: function onBlur(e) { _this2.$emit("blur", e); }, onFocus: _this2.handleFocus, onKeyPress: function onKeyPress(e) { _this2.$emit("keyPress", e); }, onKeyDown: function onKeyDown(e) { return _this2.handleKeyDown(e, highlightedIndex); }, onKeyUp: function onKeyUp(e) { _this2.$emit("keyUp", e); } })), "domProps": _extends({}, getInputProps({ value: currentValue ? currentValue : "" })) }), _this2.renderIcons(), renderAllSuggestions && renderAllSuggestions({ currentValue: currentValue, isOpen: isOpen, getItemProps: getItemProps, getItemEvents: getItemEvents, highlightedIndex: highlightedIndex, parsedSuggestions: suggestionsList }), _this2.renderErrorComponent(), !renderAllSuggestions && isOpen && suggestionsList.length ? h("ul", { "class": suggestions + " " + getClassName(innerClass, "list") }, [suggestionsList.slice(0, 10).map(function (item, index) { return h("li", { "domProps": _extends({}, getItemProps({ item: item })), "on": _extends({}, getItemEvents({ item: item })), "key": index + 1 + "-" + item.value, "style": { backgroundColor: _this2.getBackgroundColor(highlightedIndex, index) } }, [h(SuggestionItem, { "attrs": { "currentValue": currentValue, "suggestion": item } })]); })]) : _this2.renderNoSuggestionComponent()]); } } }) : h("div", { "class": suggestionsContainer }, [h(Input, { "class": getClassName(innerClass, "input") || "", "attrs": { "placeholder": placeholder, "iconPosition": iconPosition, "showIcon": showIcon, "showClear": showClear, "innerRef": innerRef }, "on": _extends({}, { blur: function blur(e) { _this2.$emit("blur", e); }, keypress: function keypress(e) { _this2.$emit("keyPress", e); }, input: this.onInputChange, focus: function focus(e) { _this2.$emit("focus", e); }, keydown: function keydown(e) { _this2.$emit("keyDown", e); }, keyup: function keyup(e) { _this2.$emit("keyUp", e); } }), "domProps": _extends({}, { autofocus: autoFocus, value: currentValue ? currentValue : "" }) }), this.renderIcons()])]); } }; var VueSearchboxWrapper = { render: function render() { var h = arguments[0]; return h(VueSearchbox, { "attrs": _extends({}, this.$attrs, { "currentURL": window.location.href }) }); } }; // Import vue component function install(Vue) { if (install.installed) return; install.installed = true; Vue.component('VueSearchbox', VueSearchboxWrapper); } // Create module definition for Vue.use() var plugin = { install: install }; // To auto-install when vue is found /* global window global */ var GlobalVue = null; if (typeof window !== 'undefined') { GlobalVue = window.Vue; } else if (typeof global !== 'undefined') { GlobalVue = global.Vue; } if (GlobalVue) { GlobalVue.use(plugin); } // Inject install function into component - allows component // to be registered via Vue.use() as well as Vue.component() VueSearchboxWrapper.install = install; // Export component by default // also be used as directives, etc. - eg. import { RollupDemoDirective } from 'rollup-demo'; // export const RollupDemoDirective = component; export default VueSearchboxWrapper;