@atlaskit/quick-search 8.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +763 -0
- package/LICENSE +13 -0
- package/build/tsconfig.json +17 -0
- package/dist/cjs/components/QuickSearch.js +447 -0
- package/dist/cjs/components/ResultItem/ResultItem.js +87 -0
- package/dist/cjs/components/ResultItem/ResultItemGroup.js +57 -0
- package/dist/cjs/components/ResultItem/styled.js +53 -0
- package/dist/cjs/components/Results/ContainerResult.js +93 -0
- package/dist/cjs/components/Results/ObjectResult.js +108 -0
- package/dist/cjs/components/Results/PersonResult.js +99 -0
- package/dist/cjs/components/Results/ResultBase.js +206 -0
- package/dist/cjs/components/Results/index.js +39 -0
- package/dist/cjs/components/Results/types.js +5 -0
- package/dist/cjs/components/Search/Search.js +124 -0
- package/dist/cjs/components/Search/styled.js +61 -0
- package/dist/cjs/components/constants.js +20 -0
- package/dist/cjs/components/context.js +29 -0
- package/dist/cjs/components/decorateWithAnalyticsData.js +80 -0
- package/dist/cjs/components/isReactElement.js +19 -0
- package/dist/cjs/index.js +94 -0
- package/dist/cjs/version.json +4 -0
- package/dist/es2019/components/QuickSearch.js +417 -0
- package/dist/es2019/components/ResultItem/ResultItem.js +41 -0
- package/dist/es2019/components/ResultItem/ResultItemGroup.js +16 -0
- package/dist/es2019/components/ResultItem/styled.js +54 -0
- package/dist/es2019/components/Results/ContainerResult.js +45 -0
- package/dist/es2019/components/Results/ObjectResult.js +60 -0
- package/dist/es2019/components/Results/PersonResult.js +50 -0
- package/dist/es2019/components/Results/ResultBase.js +149 -0
- package/dist/es2019/components/Results/index.js +4 -0
- package/dist/es2019/components/Results/types.js +1 -0
- package/dist/es2019/components/Search/Search.js +80 -0
- package/dist/es2019/components/Search/styled.js +76 -0
- package/dist/es2019/components/constants.js +7 -0
- package/dist/es2019/components/context.js +11 -0
- package/dist/es2019/components/decorateWithAnalyticsData.js +33 -0
- package/dist/es2019/components/isReactElement.js +10 -0
- package/dist/es2019/index.js +23 -0
- package/dist/es2019/version.json +4 -0
- package/dist/esm/components/QuickSearch.js +442 -0
- package/dist/esm/components/ResultItem/ResultItem.js +65 -0
- package/dist/esm/components/ResultItem/ResultItemGroup.js +42 -0
- package/dist/esm/components/ResultItem/styled.js +18 -0
- package/dist/esm/components/Results/ContainerResult.js +78 -0
- package/dist/esm/components/Results/ObjectResult.js +93 -0
- package/dist/esm/components/Results/PersonResult.js +86 -0
- package/dist/esm/components/Results/ResultBase.js +189 -0
- package/dist/esm/components/Results/index.js +4 -0
- package/dist/esm/components/Results/types.js +1 -0
- package/dist/esm/components/Search/Search.js +108 -0
- package/dist/esm/components/Search/styled.js +20 -0
- package/dist/esm/components/constants.js +7 -0
- package/dist/esm/components/context.js +13 -0
- package/dist/esm/components/decorateWithAnalyticsData.js +64 -0
- package/dist/esm/components/isReactElement.js +10 -0
- package/dist/esm/index.js +23 -0
- package/dist/esm/version.json +4 -0
- package/dist/types/components/QuickSearch.d.ts +122 -0
- package/dist/types/components/ResultItem/ResultItem.d.ts +38 -0
- package/dist/types/components/ResultItem/ResultItemGroup.d.ts +11 -0
- package/dist/types/components/ResultItem/styled.d.ts +13 -0
- package/dist/types/components/Results/ContainerResult.d.ts +19 -0
- package/dist/types/components/Results/ObjectResult.d.ts +22 -0
- package/dist/types/components/Results/PersonResult.d.ts +20 -0
- package/dist/types/components/Results/ResultBase.d.ts +37 -0
- package/dist/types/components/Results/index.d.ts +4 -0
- package/dist/types/components/Results/types.d.ts +34 -0
- package/dist/types/components/Search/Search.d.ts +31 -0
- package/dist/types/components/Search/styled.d.ts +10 -0
- package/dist/types/components/constants.d.ts +6 -0
- package/dist/types/components/context.d.ts +22 -0
- package/dist/types/components/decorateWithAnalyticsData.d.ts +3 -0
- package/dist/types/components/isReactElement.d.ts +6 -0
- package/dist/types/index.d.ts +17 -0
- package/docs/0-intro.tsx +53 -0
- package/package.json +52 -0
- package/tsconfig.json +11 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import styled, { css } from 'styled-components';
|
|
2
|
+
import { gridSize } from '@atlaskit/theme/constants';
|
|
3
|
+
import { N0, N500, B200, placeholderText, N50 } from '@atlaskit/theme/colors';
|
|
4
|
+
const inputRightPadding = gridSize() * 2;
|
|
5
|
+
export const SearchBox = styled.div`
|
|
6
|
+
position: sticky;
|
|
7
|
+
top: 0;
|
|
8
|
+
z-index: 1; /* required to keep the search box on top of icons in results when sticky */
|
|
9
|
+
background-color: ${N0};
|
|
10
|
+
color: ${N500};
|
|
11
|
+
display: flex;
|
|
12
|
+
height: 36px;
|
|
13
|
+
z-index: 10;
|
|
14
|
+
`;
|
|
15
|
+
export const SearchFieldBaseOuter = styled.div`
|
|
16
|
+
display: flex;
|
|
17
|
+
flex: 1;
|
|
18
|
+
margin-right: auto;
|
|
19
|
+
padding-bottom: 2px;
|
|
20
|
+
border-bottom: 2px solid ${B200};
|
|
21
|
+
`;
|
|
22
|
+
export const SearchFieldBaseInner = styled.div`
|
|
23
|
+
position: relative;
|
|
24
|
+
align-items: center;
|
|
25
|
+
padding-right: ${inputRightPadding}px; /* pad search text from FieldBase's isLoading spinner */
|
|
26
|
+
display: flex;
|
|
27
|
+
flex-grow: 1;
|
|
28
|
+
`;
|
|
29
|
+
export const SearchInner = styled.div`
|
|
30
|
+
padding-right: ${gridSize() * 3}px;
|
|
31
|
+
`;
|
|
32
|
+
export const getPlaceholderStyle = style => css`
|
|
33
|
+
&::-webkit-input-placeholder {
|
|
34
|
+
${style};
|
|
35
|
+
}
|
|
36
|
+
&::-moz-placeholder {
|
|
37
|
+
/* Mozilla Firefox 19+ */
|
|
38
|
+
${style} opacity: 1;
|
|
39
|
+
}
|
|
40
|
+
&::-ms-input-placeholder {
|
|
41
|
+
/* Microsoft Edge */
|
|
42
|
+
${style};
|
|
43
|
+
}
|
|
44
|
+
&:-moz-placeholder {
|
|
45
|
+
/* Mozilla Firefox 4 to 18 */
|
|
46
|
+
${style} opacity: 1;
|
|
47
|
+
}
|
|
48
|
+
&:-ms-input-placeholder {
|
|
49
|
+
/* Internet Explorer 10-11 */
|
|
50
|
+
${style};
|
|
51
|
+
}
|
|
52
|
+
`;
|
|
53
|
+
export const getPlaceholderColor = css`
|
|
54
|
+
color: ${placeholderText};
|
|
55
|
+
`;
|
|
56
|
+
export const SearchInput = styled.input`
|
|
57
|
+
background-color: transparent;
|
|
58
|
+
border: 0;
|
|
59
|
+
color: ${N500};
|
|
60
|
+
flex-grow: 1;
|
|
61
|
+
font-size: 1.4em;
|
|
62
|
+
outline: 0;
|
|
63
|
+
// Safari adds 2px margin-left
|
|
64
|
+
margin-left: 0;
|
|
65
|
+
${getPlaceholderStyle(getPlaceholderColor)};
|
|
66
|
+
`;
|
|
67
|
+
export const SearchInputTypeAhead = styled(SearchInput)`
|
|
68
|
+
color: ${N50};
|
|
69
|
+
position: absolute;
|
|
70
|
+
width: calc(100% - ${inputRightPadding}px);
|
|
71
|
+
z-index: -1;
|
|
72
|
+
`;
|
|
73
|
+
export const SearchInputControlsContainer = styled.span`
|
|
74
|
+
padding-left: ${gridSize() * 3}px;
|
|
75
|
+
`;
|
|
76
|
+
SearchInputControlsContainer.displayName = 'SearchInputControlsContainer'; // required for testing
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/* eslint-disable import/prefer-default-export */
|
|
2
|
+
export const ATLASKIT_QUICKSEARCH_NS = 'atlaskit.navigation.quick-search';
|
|
3
|
+
export const QS_ANALYTICS_EV_CLOSE = `${ATLASKIT_QUICKSEARCH_NS}.close`;
|
|
4
|
+
export const QS_ANALYTICS_EV_KB_CTRLS_USED = `${ATLASKIT_QUICKSEARCH_NS}.keyboard-controls-used`;
|
|
5
|
+
export const QS_ANALYTICS_EV_OPEN = `${ATLASKIT_QUICKSEARCH_NS}.open`;
|
|
6
|
+
export const QS_ANALYTICS_EV_QUERY_ENTERED = `${ATLASKIT_QUICKSEARCH_NS}.query-entered`;
|
|
7
|
+
export const QS_ANALYTICS_EV_SUBMIT = `${ATLASKIT_QUICKSEARCH_NS}.submit`;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
const defaultState = {
|
|
3
|
+
sendAnalytics: () => {},
|
|
4
|
+
onMouseEnter: () => {},
|
|
5
|
+
onMouseLeave: () => {},
|
|
6
|
+
registerResult: () => {},
|
|
7
|
+
unregisterResult: () => {},
|
|
8
|
+
getIndex: n => Number(n)
|
|
9
|
+
};
|
|
10
|
+
export const ResultContext = /*#__PURE__*/React.createContext(defaultState);
|
|
11
|
+
export const SelectedResultIdContext = /*#__PURE__*/React.createContext(null);
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { AnalyticsDecorator } from '@atlaskit/analytics';
|
|
4
|
+
import isReactElement from './isReactElement';
|
|
5
|
+
import { QS_ANALYTICS_EV_SUBMIT } from './constants';
|
|
6
|
+
export default function decorateWithAnalyticsData(WrappedQuickSearch) {
|
|
7
|
+
var _class, _temp;
|
|
8
|
+
|
|
9
|
+
return _temp = _class = class DecorateWithAnalyticsData extends React.Component {
|
|
10
|
+
constructor(...args) {
|
|
11
|
+
super(...args);
|
|
12
|
+
|
|
13
|
+
_defineProperty(this, "countChildren", () => {
|
|
14
|
+
return React.Children.toArray(this.props.children).reduce((total, group) => isReactElement(group) ? total + React.Children.count(group.props.children) : total, 0);
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
render() {
|
|
19
|
+
return /*#__PURE__*/React.createElement(AnalyticsDecorator, {
|
|
20
|
+
matchPrivate: true,
|
|
21
|
+
match: QS_ANALYTICS_EV_SUBMIT,
|
|
22
|
+
data: {
|
|
23
|
+
resultCount: this.countChildren(),
|
|
24
|
+
queryLength: this.props.value.length
|
|
25
|
+
}
|
|
26
|
+
}, /*#__PURE__*/React.createElement(WrappedQuickSearch, this.props));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
}, _defineProperty(_class, "defaultProps", {
|
|
30
|
+
children: [],
|
|
31
|
+
value: ''
|
|
32
|
+
}), _temp;
|
|
33
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Heuristically check whether an element is a react element or not.
|
|
3
|
+
* React elements have constructors for their type property but native elements use strings.
|
|
4
|
+
*/
|
|
5
|
+
export default (element => {
|
|
6
|
+
const type = element && element.type;
|
|
7
|
+
const hasFunctionAsType = !!type && typeof type === 'function';
|
|
8
|
+
const hasProps = element && element.props;
|
|
9
|
+
return hasFunctionAsType && hasProps;
|
|
10
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as resultTypes from './components/Results';
|
|
2
|
+
/*
|
|
3
|
+
This component is exported in two different ways.
|
|
4
|
+
|
|
5
|
+
v0: A legacy, backwards compatible API from when quick-search was living inside @atlaskit/navigation. This API
|
|
6
|
+
is deprecated and will be removed in the next major version.
|
|
7
|
+
|
|
8
|
+
v1: An API tailored to a stand-alone quick-search component.
|
|
9
|
+
*/
|
|
10
|
+
// API v0 Exports:
|
|
11
|
+
|
|
12
|
+
export { default as AkNavigationItemGroup } from './components/ResultItem/ResultItemGroup';
|
|
13
|
+
export { default as AkNavigationItem } from './components/ResultItem/ResultItem';
|
|
14
|
+
export { default as AkQuickSearch } from './components/QuickSearch';
|
|
15
|
+
export { default as AkSearch } from './components/Search/Search';
|
|
16
|
+
export { resultTypes as quickSearchResultTypes }; // API v1 Exports:
|
|
17
|
+
|
|
18
|
+
export { default as QuickSearch } from './components/QuickSearch';
|
|
19
|
+
export { default as ResultItemGroup } from './components/ResultItem/ResultItemGroup';
|
|
20
|
+
export { default as ObjectResult } from './components/Results/ObjectResult';
|
|
21
|
+
export { default as PersonResult } from './components/Results/PersonResult';
|
|
22
|
+
export { default as ContainerResult } from './components/Results/ContainerResult';
|
|
23
|
+
export { default as ResultBase } from './components/Results/ResultBase'; // types
|
|
@@ -0,0 +1,442 @@
|
|
|
1
|
+
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
|
|
2
|
+
import _createClass from "@babel/runtime/helpers/createClass";
|
|
3
|
+
import _assertThisInitialized from "@babel/runtime/helpers/assertThisInitialized";
|
|
4
|
+
import _inherits from "@babel/runtime/helpers/inherits";
|
|
5
|
+
import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn";
|
|
6
|
+
import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";
|
|
7
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
8
|
+
|
|
9
|
+
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
|
|
10
|
+
|
|
11
|
+
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
|
|
12
|
+
|
|
13
|
+
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
|
|
14
|
+
|
|
15
|
+
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
|
|
16
|
+
|
|
17
|
+
import React from 'react';
|
|
18
|
+
import keycode from 'keycode';
|
|
19
|
+
import { withAnalytics } from '@atlaskit/analytics';
|
|
20
|
+
import AkSearch from './Search/Search';
|
|
21
|
+
import { ResultContext, SelectedResultIdContext } from './context';
|
|
22
|
+
import decorateWithAnalyticsData from './decorateWithAnalyticsData';
|
|
23
|
+
import { QS_ANALYTICS_EV_CLOSE, QS_ANALYTICS_EV_KB_CTRLS_USED, QS_ANALYTICS_EV_OPEN, QS_ANALYTICS_EV_QUERY_ENTERED, QS_ANALYTICS_EV_SUBMIT } from './constants';
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Get the result ID of a result by its index in the flatResults array
|
|
27
|
+
* Returns null for a failed index or if resultId is empty|undefined
|
|
28
|
+
*/
|
|
29
|
+
var getResultIdByIndex = function getResultIdByIndex(array, index) {
|
|
30
|
+
if (array && index !== null && array[index] && array[index].props && array[index].props.resultId) {
|
|
31
|
+
return array[index].props.resultId;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return null;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Find a result in the flatResults array by its ID
|
|
38
|
+
* Returns the result object or null
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
var getResultById = function getResultById(array, id) {
|
|
43
|
+
return array && array.find(function (result) {
|
|
44
|
+
return result.props && result.props.resultId === id;
|
|
45
|
+
}) || null;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Get a result's index in the flatResults array by its ID
|
|
49
|
+
* Returns a numeric index or null
|
|
50
|
+
*/
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
var getResultIndexById = function getResultIndexById(array, id) {
|
|
54
|
+
if (!array) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
var result = getResultById(array, id);
|
|
59
|
+
|
|
60
|
+
if (!result) {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
var index = array.indexOf(result);
|
|
65
|
+
return index >= 0 ? index : null;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
var adjustIndex = function adjustIndex(arrayLength, currentIndex, adjustment) {
|
|
69
|
+
if (arrayLength === 0) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (adjustment === 0) {
|
|
74
|
+
return currentIndex;
|
|
75
|
+
} // If nothing is selected, select the element on the end
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
if (currentIndex === null) {
|
|
79
|
+
return adjustment > 0 ? 0 : arrayLength - 1;
|
|
80
|
+
} // Adjust current index, wrapping around if necessary
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
var adjustedIndex = (currentIndex + adjustment) % arrayLength; // Correct for negative indices
|
|
84
|
+
|
|
85
|
+
return adjustedIndex >= 0 ? adjustedIndex : adjustedIndex + arrayLength;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export var QuickSearch = /*#__PURE__*/function (_React$Component) {
|
|
89
|
+
_inherits(QuickSearch, _React$Component);
|
|
90
|
+
|
|
91
|
+
var _super = _createSuper(QuickSearch);
|
|
92
|
+
|
|
93
|
+
function QuickSearch(props) {
|
|
94
|
+
var _this;
|
|
95
|
+
|
|
96
|
+
_classCallCheck(this, QuickSearch);
|
|
97
|
+
|
|
98
|
+
_this = _super.call(this, props);
|
|
99
|
+
|
|
100
|
+
_defineProperty(_assertThisInitialized(_this), "flatResults", []);
|
|
101
|
+
|
|
102
|
+
_defineProperty(_assertThisInitialized(_this), "hasSearchQueryEventFired", false);
|
|
103
|
+
|
|
104
|
+
_defineProperty(_assertThisInitialized(_this), "hasKeyDownEventFired", false);
|
|
105
|
+
|
|
106
|
+
_defineProperty(_assertThisInitialized(_this), "lastKeyPressed", '');
|
|
107
|
+
|
|
108
|
+
_defineProperty(_assertThisInitialized(_this), "adjustSelectedResultIndex", function (adjustment) {
|
|
109
|
+
var currentIndex = getResultIndexById(_this.flatResults, _this.state.selectedResultId);
|
|
110
|
+
var newIndex = adjustIndex(_this.flatResults.length, currentIndex, adjustment);
|
|
111
|
+
var selectedResultId = getResultIdByIndex(_this.flatResults, newIndex);
|
|
112
|
+
|
|
113
|
+
_this.setState({
|
|
114
|
+
selectedResultId: selectedResultId
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
if (selectedResultId) {
|
|
118
|
+
_this.fireKeyboardControlEvent(selectedResultId);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (_this.props.onSelectedResultIdChanged) {
|
|
122
|
+
_this.props.onSelectedResultIdChanged(selectedResultId);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
_defineProperty(_assertThisInitialized(_this), "selectNext", function () {
|
|
127
|
+
_this.adjustSelectedResultIndex(+1);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
_defineProperty(_assertThisInitialized(_this), "selectPrevious", function () {
|
|
131
|
+
_this.adjustSelectedResultIndex(-1);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
_defineProperty(_assertThisInitialized(_this), "handleRegisterResult", function (result) {
|
|
135
|
+
if (!getResultById(_this.flatResults, result.props.resultId)) {
|
|
136
|
+
_this.flatResults.push(result);
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
_defineProperty(_assertThisInitialized(_this), "handleUnregisterResult", function (result) {
|
|
141
|
+
var resultIndex = getResultIndexById(_this.flatResults, result.props.resultId);
|
|
142
|
+
|
|
143
|
+
if (resultIndex !== null && +resultIndex >= 0) {
|
|
144
|
+
_this.flatResults.splice(resultIndex, 1);
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
_defineProperty(_assertThisInitialized(_this), "handleResultMouseEnter", function (resultData) {
|
|
149
|
+
_this.setState({
|
|
150
|
+
selectedResultId: resultData && resultData.resultId
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
_defineProperty(_assertThisInitialized(_this), "handleResultMouseLeave", function () {
|
|
155
|
+
_this.setState({
|
|
156
|
+
selectedResultId: null
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
_defineProperty(_assertThisInitialized(_this), "handleSearchBlur", function (event) {
|
|
161
|
+
_this.props.onSearchBlur(event);
|
|
162
|
+
|
|
163
|
+
_this.setState({
|
|
164
|
+
selectedResultId: null
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
_defineProperty(_assertThisInitialized(_this), "onInput", function (event) {
|
|
169
|
+
var onSearchInput = _this.props.onSearchInput;
|
|
170
|
+
|
|
171
|
+
_this.setState({
|
|
172
|
+
value: event.currentTarget.value
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
if (onSearchInput) {
|
|
176
|
+
onSearchInput(event);
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
_defineProperty(_assertThisInitialized(_this), "handleSearchKeyDown", function (event) {
|
|
181
|
+
var firePrivateAnalyticsEvent = _this.props.firePrivateAnalyticsEvent;
|
|
182
|
+
|
|
183
|
+
_this.props.onSearchKeyDown(event);
|
|
184
|
+
|
|
185
|
+
_this.lastKeyPressed = event.key; // Need to check for keyCode for up/down/enter in case user is composing using an IME
|
|
186
|
+
// fixes https://ecosystem.atlassian.net/browse/DS-6518
|
|
187
|
+
|
|
188
|
+
if (event.key === 'ArrowUp' && event.keyCode === keycode('up')) {
|
|
189
|
+
event.preventDefault(); // Don't move cursor around in search input field
|
|
190
|
+
|
|
191
|
+
_this.selectPrevious();
|
|
192
|
+
} else if (event.key === 'ArrowDown' && event.keyCode === keycode('down')) {
|
|
193
|
+
event.preventDefault(); // Don't move cursor around in search input field
|
|
194
|
+
|
|
195
|
+
_this.selectNext();
|
|
196
|
+
} else if (event.key === 'Enter' && event.keyCode === keycode('enter')) {
|
|
197
|
+
// shift key pressed or no result selected
|
|
198
|
+
if (event.shiftKey || !_this.state.selectedResultId) {
|
|
199
|
+
if (firePrivateAnalyticsEvent) {
|
|
200
|
+
firePrivateAnalyticsEvent(QS_ANALYTICS_EV_SUBMIT, {
|
|
201
|
+
newTab: false,
|
|
202
|
+
// enter always open in the same tab
|
|
203
|
+
resultCount: _this.flatResults.length,
|
|
204
|
+
method: 'shortcut'
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
_this.props.onSearchSubmit(event);
|
|
209
|
+
} else {
|
|
210
|
+
event.preventDefault(); // Don't fire submit event from input
|
|
211
|
+
|
|
212
|
+
var result = getResultById(_this.flatResults, _this.state.selectedResultId);
|
|
213
|
+
|
|
214
|
+
if (!result || !result.props) {
|
|
215
|
+
return;
|
|
216
|
+
} // Capture when users are using the keyboard to submit
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
if (typeof firePrivateAnalyticsEvent === 'function') {
|
|
220
|
+
_this.fireKeyboardControlEvent(_this.state.selectedResultId);
|
|
221
|
+
|
|
222
|
+
firePrivateAnalyticsEvent(QS_ANALYTICS_EV_SUBMIT, _objectSpread(_objectSpread({}, result.getAnalyticsData()), {}, {
|
|
223
|
+
method: 'returnKey',
|
|
224
|
+
newTab: false,
|
|
225
|
+
// enter always open in the same tab
|
|
226
|
+
resultCount: _this.flatResults.length
|
|
227
|
+
}));
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
var _preventDefault = false;
|
|
231
|
+
|
|
232
|
+
if (result.props.onClick) {
|
|
233
|
+
result.props.onClick({
|
|
234
|
+
resultId: result.props.resultId,
|
|
235
|
+
type: result.props.type,
|
|
236
|
+
event: Object.assign({}, event, {
|
|
237
|
+
preventDefault: function preventDefault() {
|
|
238
|
+
_preventDefault = true;
|
|
239
|
+
},
|
|
240
|
+
stopPropagation: function stopPropagation() {}
|
|
241
|
+
})
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (result.props.href && !_preventDefault) {
|
|
246
|
+
window.location.assign(result.props.href);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
} else if (event.key === 'Tab' || event.key === 'ArrowRight') {
|
|
250
|
+
var autocompleteText = _this.props.autocompleteText;
|
|
251
|
+
|
|
252
|
+
if (autocompleteText && autocompleteText.length > 0 && // multiple Tab or ArrowRight
|
|
253
|
+
autocompleteText.slice(-1) !== ' ') {
|
|
254
|
+
_this.acceptAutocomplete(event, autocompleteText);
|
|
255
|
+
|
|
256
|
+
event.preventDefault();
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
_defineProperty(_assertThisInitialized(_this), "acceptAutocomplete", function (event, text) {
|
|
262
|
+
var onSearchInput = _this.props.onSearchInput;
|
|
263
|
+
var newValue = "".concat(text, " ");
|
|
264
|
+
|
|
265
|
+
if (_this.inputSearchRef) {
|
|
266
|
+
_this.setState({
|
|
267
|
+
value: newValue
|
|
268
|
+
}); // @ts-ignore unchecked
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
_this.inputSearchRef.value = newValue;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (onSearchInput) {
|
|
275
|
+
onSearchInput(event, true);
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
_defineProperty(_assertThisInitialized(_this), "setSearchInputRef", function (refs) {
|
|
280
|
+
if (refs && refs.inputRef) {
|
|
281
|
+
_this.inputSearchRef = refs.inputRef;
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
_defineProperty(_assertThisInitialized(_this), "focusSearchInput", function () {
|
|
286
|
+
if (_this.inputSearchRef && // @ts-ignore unchecked
|
|
287
|
+
typeof _this.inputSearchRef.focus === 'function') {
|
|
288
|
+
// @ts-ignore unchecked
|
|
289
|
+
_this.inputSearchRef.focus();
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
_this.state = {
|
|
294
|
+
/** Select first result by default if `selectedResultId` prop is not provided */
|
|
295
|
+
selectedResultId: _this.props.selectedResultId || null,
|
|
296
|
+
context: {
|
|
297
|
+
registerResult: _this.handleRegisterResult,
|
|
298
|
+
unregisterResult: _this.handleUnregisterResult,
|
|
299
|
+
onMouseEnter: _this.handleResultMouseEnter,
|
|
300
|
+
onMouseLeave: _this.handleResultMouseLeave,
|
|
301
|
+
sendAnalytics: _this.props.firePrivateAnalyticsEvent,
|
|
302
|
+
getIndex: function getIndex(resultId) {
|
|
303
|
+
return getResultIndexById(_this.flatResults, resultId);
|
|
304
|
+
},
|
|
305
|
+
linkComponent: _this.props.linkComponent
|
|
306
|
+
},
|
|
307
|
+
value: props.value
|
|
308
|
+
};
|
|
309
|
+
return _this;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
_createClass(QuickSearch, [{
|
|
313
|
+
key: "componentDidMount",
|
|
314
|
+
value: function componentDidMount() {
|
|
315
|
+
var firePrivateAnalyticsEvent = this.props.firePrivateAnalyticsEvent;
|
|
316
|
+
|
|
317
|
+
if (firePrivateAnalyticsEvent) {
|
|
318
|
+
firePrivateAnalyticsEvent(QS_ANALYTICS_EV_OPEN, {});
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}, {
|
|
322
|
+
key: "componentWillUnmount",
|
|
323
|
+
value: function componentWillUnmount() {
|
|
324
|
+
var firePrivateAnalyticsEvent = this.props.firePrivateAnalyticsEvent;
|
|
325
|
+
|
|
326
|
+
if (firePrivateAnalyticsEvent) {
|
|
327
|
+
firePrivateAnalyticsEvent(QS_ANALYTICS_EV_CLOSE, {});
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}, {
|
|
331
|
+
key: "UNSAFE_componentWillReceiveProps",
|
|
332
|
+
value: function UNSAFE_componentWillReceiveProps(nextProps) {
|
|
333
|
+
if (nextProps.children !== this.props.children) {
|
|
334
|
+
this.setState({
|
|
335
|
+
selectedResultId: nextProps.selectedResultId || null
|
|
336
|
+
});
|
|
337
|
+
} else if (nextProps.selectedResultId !== this.props.selectedResultId && nextProps.selectedResultId !== this.state.selectedResultId) {
|
|
338
|
+
this.setState({
|
|
339
|
+
selectedResultId: nextProps.selectedResultId || null
|
|
340
|
+
});
|
|
341
|
+
} // keep context state in sync
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
var _this$state$context = this.state.context,
|
|
345
|
+
sendAnalytics = _this$state$context.sendAnalytics,
|
|
346
|
+
linkComponent = _this$state$context.linkComponent;
|
|
347
|
+
|
|
348
|
+
if (sendAnalytics !== nextProps.firePrivateAnalyticsEvent || linkComponent !== nextProps.linkComponent) {
|
|
349
|
+
this.setState({
|
|
350
|
+
context: _objectSpread(_objectSpread({}, this.state.context), {}, {
|
|
351
|
+
sendAnalytics: nextProps.firePrivateAnalyticsEvent,
|
|
352
|
+
linkComponent: nextProps.linkComponent
|
|
353
|
+
})
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Capture whether user needed to query in order to find their target result.
|
|
358
|
+
* Only fire once per mount. Only fire when a search term is entered and the previous search
|
|
359
|
+
* term was empty.
|
|
360
|
+
*/
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
if (!this.hasSearchQueryEventFired && !this.props.value && nextProps.value) {
|
|
364
|
+
this.hasSearchQueryEventFired = true;
|
|
365
|
+
var firePrivateAnalyticsEvent = this.props.firePrivateAnalyticsEvent;
|
|
366
|
+
|
|
367
|
+
if (firePrivateAnalyticsEvent) {
|
|
368
|
+
firePrivateAnalyticsEvent(QS_ANALYTICS_EV_QUERY_ENTERED, {});
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}, {
|
|
373
|
+
key: "fireKeyboardControlEvent",
|
|
374
|
+
value: function fireKeyboardControlEvent(selectedResultId) {
|
|
375
|
+
var firePrivateAnalyticsEvent = this.props.firePrivateAnalyticsEvent;
|
|
376
|
+
|
|
377
|
+
if (firePrivateAnalyticsEvent) {
|
|
378
|
+
var result = getResultById(this.flatResults, selectedResultId);
|
|
379
|
+
|
|
380
|
+
if (result) {
|
|
381
|
+
firePrivateAnalyticsEvent(QS_ANALYTICS_EV_KB_CTRLS_USED, _objectSpread(_objectSpread({}, result.getAnalyticsData()), {}, {
|
|
382
|
+
key: this.lastKeyPressed,
|
|
383
|
+
resultCount: this.flatResults.length
|
|
384
|
+
}));
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
this.lastKeyPressed = '';
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Uses the virtual list, this.flatResults, to move the selection across grouped results as if
|
|
392
|
+
* results were in a single, circular list.
|
|
393
|
+
*
|
|
394
|
+
* Process:
|
|
395
|
+
* 1. Finds the index of the selected result in the flatResults array,
|
|
396
|
+
* 2. Increments or decrements this index by the supplied adjustment amount,
|
|
397
|
+
* 3. Sets the new selectedResultId based on the modifed index
|
|
398
|
+
*/
|
|
399
|
+
|
|
400
|
+
}, {
|
|
401
|
+
key: "render",
|
|
402
|
+
value: function render() {
|
|
403
|
+
return /*#__PURE__*/React.createElement(AkSearch, {
|
|
404
|
+
isLoading: this.props.isLoading,
|
|
405
|
+
inputControls: this.props.inputControls,
|
|
406
|
+
onBlur: this.handleSearchBlur,
|
|
407
|
+
onInput: this.onInput,
|
|
408
|
+
onKeyDown: this.handleSearchKeyDown,
|
|
409
|
+
placeholder: this.props.placeholder,
|
|
410
|
+
value: this.state.value,
|
|
411
|
+
autocompleteText: this.props.autocompleteText,
|
|
412
|
+
ref: this.setSearchInputRef
|
|
413
|
+
}, /*#__PURE__*/React.createElement(ResultContext.Provider, {
|
|
414
|
+
value: this.state.context
|
|
415
|
+
}, /*#__PURE__*/React.createElement(SelectedResultIdContext.Provider, {
|
|
416
|
+
value: this.state.selectedResultId
|
|
417
|
+
}, this.props.children)));
|
|
418
|
+
}
|
|
419
|
+
}]);
|
|
420
|
+
|
|
421
|
+
return QuickSearch;
|
|
422
|
+
}(React.Component);
|
|
423
|
+
/**
|
|
424
|
+
* HOCs:
|
|
425
|
+
* `decorateWithAnalyticsData` - Wrapper that decorates analytics events with additional data.
|
|
426
|
+
* `withAnalytics` - Injects analytics firing methods that are picked up by
|
|
427
|
+
* @atlaskit/analytics/AnalyticsListener.
|
|
428
|
+
*/
|
|
429
|
+
|
|
430
|
+
_defineProperty(QuickSearch, "defaultProps", {
|
|
431
|
+
children: [],
|
|
432
|
+
firePrivateAnalyticsEvent: function firePrivateAnalyticsEvent(_) {},
|
|
433
|
+
isLoading: false,
|
|
434
|
+
onSearchBlur: function onSearchBlur(_) {},
|
|
435
|
+
onSearchKeyDown: function onSearchKeyDown(_) {},
|
|
436
|
+
onSearchSubmit: function onSearchSubmit(_) {},
|
|
437
|
+
placeholder: 'Search',
|
|
438
|
+
value: ''
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
export default decorateWithAnalyticsData( // @ts-ignore
|
|
442
|
+
withAnalytics(QuickSearch, {}, {}));
|