vue-searchbox
Version:
Lightweight searchbox component for Vue
1,487 lines (1,334 loc) • 46.6 kB
JavaScript
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;