@atlaskit/link-picker 1.6.1 → 1.8.0

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.
Files changed (57) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/cjs/analytics.codegen.js +28 -0
  3. package/dist/cjs/common/constants.js +10 -0
  4. package/dist/cjs/{ui/error-boundary-fallback → common}/generic-error-svg/index.js +0 -0
  5. package/dist/cjs/{ui/error-boundary-fallback → common}/generic-error-svg/styled.js +0 -0
  6. package/dist/cjs/services/use-plugins/index.js +32 -35
  7. package/dist/cjs/services/use-search-query/index.js +41 -0
  8. package/dist/cjs/ui/error-boundary-fallback/index.js +1 -1
  9. package/dist/cjs/ui/index.js +4 -4
  10. package/dist/cjs/ui/link-picker/index.js +74 -46
  11. package/dist/cjs/ui/link-picker/link-search-error/index.js +27 -0
  12. package/dist/cjs/ui/link-picker/messages.js +10 -0
  13. package/dist/cjs/ui/link-picker/text-input/index.js +4 -10
  14. package/dist/cjs/ui/link-picker/url.js +0 -5
  15. package/dist/cjs/version.json +1 -1
  16. package/dist/es2019/analytics.codegen.js +20 -0
  17. package/dist/es2019/common/constants.js +2 -0
  18. package/dist/es2019/{ui/error-boundary-fallback → common}/generic-error-svg/index.js +0 -0
  19. package/dist/es2019/{ui/error-boundary-fallback → common}/generic-error-svg/styled.js +0 -0
  20. package/dist/es2019/services/use-plugins/index.js +28 -38
  21. package/dist/es2019/services/use-search-query/index.js +32 -0
  22. package/dist/es2019/ui/error-boundary-fallback/index.js +1 -1
  23. package/dist/es2019/ui/index.js +1 -2
  24. package/dist/es2019/ui/link-picker/index.js +65 -45
  25. package/dist/es2019/ui/link-picker/link-search-error/index.js +10 -0
  26. package/dist/es2019/ui/link-picker/messages.js +10 -0
  27. package/dist/es2019/ui/link-picker/text-input/index.js +3 -9
  28. package/dist/es2019/ui/link-picker/url.js +0 -5
  29. package/dist/es2019/version.json +1 -1
  30. package/dist/esm/analytics.codegen.js +20 -0
  31. package/dist/esm/common/constants.js +2 -0
  32. package/dist/esm/{ui/error-boundary-fallback → common}/generic-error-svg/index.js +0 -0
  33. package/dist/esm/{ui/error-boundary-fallback → common}/generic-error-svg/styled.js +0 -0
  34. package/dist/esm/services/use-plugins/index.js +33 -35
  35. package/dist/esm/services/use-search-query/index.js +32 -0
  36. package/dist/esm/ui/error-boundary-fallback/index.js +1 -1
  37. package/dist/esm/ui/index.js +1 -2
  38. package/dist/esm/ui/link-picker/index.js +67 -45
  39. package/dist/esm/ui/link-picker/link-search-error/index.js +14 -0
  40. package/dist/esm/ui/link-picker/messages.js +10 -0
  41. package/dist/esm/ui/link-picker/text-input/index.js +4 -10
  42. package/dist/esm/ui/link-picker/url.js +0 -5
  43. package/dist/esm/version.json +1 -1
  44. package/dist/types/analytics.codegen.d.ts +20 -0
  45. package/dist/types/common/constants.d.ts +2 -0
  46. package/dist/types/{ui/error-boundary-fallback → common}/generic-error-svg/index.d.ts +0 -0
  47. package/dist/types/{ui/error-boundary-fallback → common}/generic-error-svg/styled.d.ts +0 -0
  48. package/dist/types/index.d.ts +1 -1
  49. package/dist/types/services/use-plugins/index.d.ts +6 -5
  50. package/dist/types/services/use-search-query/index.d.ts +3 -0
  51. package/dist/types/ui/link-picker/index.d.ts +2 -0
  52. package/dist/types/ui/link-picker/link-search-error/index.d.ts +4 -0
  53. package/dist/types/ui/link-picker/messages.d.ts +10 -0
  54. package/dist/types/ui/link-picker/text-input/index.d.ts +0 -1
  55. package/dist/types/ui/types.d.ts +5 -2
  56. package/package.json +11 -5
  57. package/report.api.md +11 -5
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # @atlaskit/link-picker
2
2
 
3
+ ## 1.8.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`89fffde2a59`](https://bitbucket.org/atlassian/atlassian-frontend/commits/89fffde2a59) - Wrap link picker in native form element
8
+
9
+ ## 1.7.1
10
+
11
+ ### Patch Changes
12
+
13
+ - [`e900714203d`](https://bitbucket.org/atlassian/atlassian-frontend/commits/e900714203d) - Add "form submitted" analytics event.
14
+
15
+ ## 1.7.0
16
+
17
+ ### Minor Changes
18
+
19
+ - [`d0feee9b4ad`](https://bitbucket.org/atlassian/atlassian-frontend/commits/d0feee9b4ad) - [ux] Add a UI error message to display when the link picker plugin resolve throws an error
20
+
3
21
  ## 1.6.1
4
22
 
5
23
  ### Patch Changes
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+
8
+ /**
9
+ * THIS FILE WAS CREATED VIA CODEGEN DO NOT MODIFY {@see http://go/af-codegen}
10
+ *
11
+ * Generates analytics utilities from the package analytics spec yaml
12
+ *
13
+ * @codegen <<SignedSource::0cc1b4d9c22b31491ded3e581114ab2c>>
14
+ * @codegenCommand yarn workspace @atlaskit/link-picker run codegen-analytics
15
+ */
16
+ function createEventPayload(eventKey, attributes) {
17
+ var event = eventKey.split('.');
18
+ return {
19
+ eventType: 'ui',
20
+ actionSubject: event[0],
21
+ action: event[1],
22
+ actionSubjectId: event[2],
23
+ attributes: attributes
24
+ };
25
+ }
26
+
27
+ var _default = createEventPayload;
28
+ exports.default = _default;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.COMPONENT_NAME = exports.ANALYTICS_CHANNEL = void 0;
7
+ var ANALYTICS_CHANNEL = 'media';
8
+ exports.ANALYTICS_CHANNEL = ANALYTICS_CHANNEL;
9
+ var COMPONENT_NAME = 'LinkPicker';
10
+ exports.COMPONENT_NAME = COMPONENT_NAME;
@@ -19,8 +19,6 @@ var _react = require("react");
19
19
 
20
20
  var _linkPicker = require("../../ui/link-picker");
21
21
 
22
- var _url = require("../../ui/link-picker/url");
23
-
24
22
  function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
25
23
 
26
24
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
@@ -29,56 +27,46 @@ function reducer(state, payload) {
29
27
  return _objectSpread(_objectSpread({}, state), payload);
30
28
  }
31
29
 
32
- function usePlugins(state, plugins) {
30
+ function usePlugins(state, activeTab, plugins) {
31
+ var _useState = (0, _react.useState)(0),
32
+ _useState2 = (0, _slicedToArray2.default)(_useState, 2),
33
+ retries = _useState2[0],
34
+ setRetries = _useState2[1];
35
+
33
36
  var _useReducer = (0, _react.useReducer)(reducer, {
34
- items: [],
37
+ items: null,
38
+ error: null,
35
39
  isLoading: false
36
40
  }),
37
41
  _useReducer2 = (0, _slicedToArray2.default)(_useReducer, 2),
38
42
  pluginState = _useReducer2[0],
39
43
  dispatch = _useReducer2[1];
40
44
 
41
- var url = state.url,
42
- selectedIndex = state.selectedIndex;
43
45
  var items = pluginState.items,
44
- isLoading = pluginState.isLoading;
45
- var activePlugin = !plugins || plugins.length === 0 ? null : plugins[state.activeTab];
46
+ isLoading = pluginState.isLoading,
47
+ error = pluginState.error;
46
48
  var queryVersion = (0, _react.useRef)(0);
47
- var pluginRef = (0, _react.useRef)(activePlugin);
48
- var selectedItem = items[selectedIndex];
49
- var isSelectedItem = (selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.url) === url;
49
+ var activePlugin = plugins === null || plugins === void 0 ? void 0 : plugins[activeTab];
50
50
  (0, _react.useEffect)(function () {
51
51
  if (!activePlugin) {
52
52
  return;
53
53
  }
54
54
 
55
- if (isSelectedItem) {
56
- return;
57
- }
58
-
59
- if ((0, _url.isSafeUrl)(url) && url.length) {
55
+ if (!state) {
60
56
  dispatch({
61
- items: [],
62
- isLoading: false
57
+ items: null,
58
+ isLoading: false,
59
+ error: null
63
60
  });
64
61
  return;
65
62
  }
66
63
 
67
- var updates = activePlugin.resolve({
68
- query: url
64
+ var updates = activePlugin.resolve(state);
65
+ dispatch({
66
+ items: null,
67
+ isLoading: true,
68
+ error: null
69
69
  });
70
-
71
- if (pluginRef.current !== activePlugin) {
72
- dispatch({
73
- items: [],
74
- isLoading: true
75
- });
76
- } else {
77
- dispatch({
78
- isLoading: true
79
- });
80
- }
81
-
82
70
  var newQuery = ++queryVersion.current;
83
71
 
84
72
  var updateResults = /*#__PURE__*/function () {
@@ -156,6 +144,8 @@ function usePlugins(state, plugins) {
156
144
  _context.prev = 25;
157
145
  _context.t0 = _context["catch"](0);
158
146
  dispatch({
147
+ error: _context.t0,
148
+ items: null,
159
149
  isLoading: false
160
150
  });
161
151
 
@@ -173,7 +163,7 @@ function usePlugins(state, plugins) {
173
163
  }();
174
164
 
175
165
  updateResults();
176
- }, [activePlugin, queryVersion, url, isSelectedItem]);
166
+ }, [activePlugin, queryVersion, state, retries]);
177
167
  var tabs = (0, _react.useMemo)(function () {
178
168
  if (!plugins || plugins.length <= 1) {
179
169
  return [];
@@ -187,12 +177,19 @@ function usePlugins(state, plugins) {
187
177
  };
188
178
  });
189
179
  }, [plugins]);
180
+ var handleRetry = (0, _react.useCallback)(function () {
181
+ setRetries(function (prev) {
182
+ return ++prev;
183
+ });
184
+ }, []);
190
185
  return {
191
186
  tabs: tabs,
192
187
  items: items,
193
188
  isLoading: isLoading,
194
- isSelectedItem: isSelectedItem,
195
- isActivePlugin: !!activePlugin
189
+ isActivePlugin: !!activePlugin,
190
+ error: error,
191
+ retry: handleRetry,
192
+ errorFallback: activePlugin === null || activePlugin === void 0 ? void 0 : activePlugin.errorFallback
196
193
  };
197
194
  }
198
195
 
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useSearchQuery = useSearchQuery;
7
+
8
+ var _react = require("react");
9
+
10
+ var _url = require("../../ui/link-picker/url");
11
+
12
+ function useSearchQuery(state) {
13
+ var _queryState$current;
14
+
15
+ var queryState = (0, _react.useRef)(null);
16
+ /*
17
+ * When state contains a valid url AND is NOT selected from results
18
+ * queryState should be null to clear the items in plugin state
19
+ */
20
+
21
+ if ((0, _url.isSafeUrl)(state.url) && state.selectedIndex === -1) {
22
+ queryState.current = null;
23
+ }
24
+ /*
25
+ * When state contains a search term e.g. Not a valid url return a query
26
+ */
27
+
28
+
29
+ if (((_queryState$current = queryState.current) === null || _queryState$current === void 0 ? void 0 : _queryState$current.query) !== state.url && !(0, _url.isSafeUrl)(state.url)) {
30
+ queryState.current = {
31
+ query: state.url
32
+ };
33
+ }
34
+ /*
35
+ * When state contains a valid url and is selected from the list
36
+ * return current state to prevent triger a new plugin search
37
+ */
38
+
39
+
40
+ return queryState.current;
41
+ }
@@ -13,7 +13,7 @@ var _emptyState = _interopRequireDefault(require("@atlaskit/empty-state"));
13
13
 
14
14
  var _reactIntlNext = require("react-intl-next");
15
15
 
16
- var _genericErrorSvg = _interopRequireDefault(require("./generic-error-svg"));
16
+ var _genericErrorSvg = _interopRequireDefault(require("../../common/generic-error-svg"));
17
17
 
18
18
  var _styled = require("../link-picker/styled");
19
19
 
@@ -15,6 +15,8 @@ var _analyticsNext = require("@atlaskit/analytics-next");
15
15
 
16
16
  var _reactLooselyLazy = require("react-loosely-lazy");
17
17
 
18
+ var _constants = require("../common/constants");
19
+
18
20
  var _version = require("../version.json");
19
21
 
20
22
  var _errorBoundaryFallback = require("./error-boundary-fallback");
@@ -25,12 +27,10 @@ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "functio
25
27
 
26
28
  function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || (0, _typeof2.default)(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
27
29
 
28
- var COMPONENT_NAME = 'LinkPicker';
29
- var ANALYTICS_CHANNEL = 'media';
30
30
  var PACKAGE_DATA = {
31
31
  packageName: _version.name,
32
32
  packageVersion: _version.version,
33
- componentName: COMPONENT_NAME
33
+ componentName: _constants.COMPONENT_NAME
34
34
  };
35
35
  var LazyLinkPicker = (0, _reactLooselyLazy.lazyForPaint)(function () {
36
36
  return Promise.resolve().then(function () {
@@ -39,7 +39,7 @@ var LazyLinkPicker = (0, _reactLooselyLazy.lazyForPaint)(function () {
39
39
  });
40
40
  var ComposedLinkPicker = /*#__PURE__*/(0, _react.memo)(function (props) {
41
41
  return /*#__PURE__*/_react.default.createElement(_analyticsNext.AnalyticsErrorBoundary, {
42
- channel: ANALYTICS_CHANNEL,
42
+ channel: _constants.ANALYTICS_CHANNEL,
43
43
  data: PACKAGE_DATA,
44
44
  ErrorComponent: _errorBoundaryFallback.ErrorBoundaryFallback
45
45
  }, /*#__PURE__*/_react.default.createElement(_reactLooselyLazy.LazySuspense, {
@@ -7,7 +7,7 @@ var _typeof = require("@babel/runtime/helpers/typeof");
7
7
  Object.defineProperty(exports, "__esModule", {
8
8
  value: true
9
9
  });
10
- exports.testIds = exports.default = exports.RECENT_SEARCH_LIST_SIZE = void 0;
10
+ exports.testIds = exports.default = exports.RECENT_SEARCH_LIST_SIZE = exports.CONTACT_SUPPORT_LINK = void 0;
11
11
 
12
12
  var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
13
13
 
@@ -21,6 +21,8 @@ var _react2 = require("@emotion/react");
21
21
 
22
22
  var _reactIntlNext = require("react-intl-next");
23
23
 
24
+ var _analyticsNext = require("@atlaskit/analytics-next");
25
+
24
26
  var _button = _interopRequireWildcard(require("@atlaskit/button"));
25
27
 
26
28
  var _form = require("@atlaskit/form");
@@ -31,6 +33,14 @@ var _tabs = _interopRequireWildcard(require("@atlaskit/tabs"));
31
33
 
32
34
  var _visuallyHidden = _interopRequireDefault(require("@atlaskit/visually-hidden"));
33
35
 
36
+ var _analytics = _interopRequireDefault(require("../../analytics.codegen"));
37
+
38
+ var _constants = require("../../common/constants");
39
+
40
+ var _usePlugins2 = require("../../services/use-plugins");
41
+
42
+ var _useSearchQuery = require("../../services/use-search-query");
43
+
34
44
  var _messages = require("./messages");
35
45
 
36
46
  var _textInput = _interopRequireDefault(require("./text-input"));
@@ -43,13 +53,13 @@ var _styled = require("./styled");
43
53
 
44
54
  var _browser = require("./browser");
45
55
 
46
- var _transformTimeStamp = require("./transformTimeStamp");
47
-
48
56
  var _announcer = _interopRequireDefault(require("./announcer"));
49
57
 
50
58
  var _linkSearchNoResults = _interopRequireDefault(require("./link-search-no-results"));
51
59
 
52
- var _usePlugins2 = require("../../services/use-plugins");
60
+ var _transformTimeStamp = require("./transformTimeStamp");
61
+
62
+ var _linkSearchError = _interopRequireDefault(require("./link-search-error"));
53
63
 
54
64
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
55
65
 
@@ -61,6 +71,8 @@ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { va
61
71
 
62
72
  var RECENT_SEARCH_LIST_SIZE = 5;
63
73
  exports.RECENT_SEARCH_LIST_SIZE = RECENT_SEARCH_LIST_SIZE;
74
+ var CONTACT_SUPPORT_LINK = 'https://support.atlassian.com/contact/';
75
+ exports.CONTACT_SUPPORT_LINK = CONTACT_SUPPORT_LINK;
64
76
  var testIds = {
65
77
  linkPicker: 'link-picker',
66
78
  urlInputField: 'link-url',
@@ -76,7 +88,8 @@ var testIds = {
76
88
  searchResultLoadingIndicator: 'link-picker.results-loading-indicator',
77
89
  urlError: 'link-error',
78
90
  tabList: 'link-picker-tabs',
79
- tabItem: 'link-picker-tab'
91
+ tabItem: 'link-picker-tab',
92
+ searchError: 'link-search-error'
80
93
  };
81
94
  exports.testIds = testIds;
82
95
  var initState = {
@@ -100,6 +113,8 @@ function reducer(state, payload) {
100
113
  }
101
114
 
102
115
  function LinkPicker(_ref) {
116
+ var _queryState$query, _items$length, _errorFallback;
117
+
103
118
  var onSubmit = _ref.onSubmit,
104
119
  onCancel = _ref.onCancel,
105
120
  onContentResize = _ref.onContentResize,
@@ -107,6 +122,9 @@ function LinkPicker(_ref) {
107
122
  initUrl = _ref.url,
108
123
  initDisplayText = _ref.displayText;
109
124
 
125
+ var _useAnalyticsEvents = (0, _analyticsNext.useAnalyticsEvents)(),
126
+ createAnalyticsEvent = _useAnalyticsEvents.createAnalyticsEvent;
127
+
110
128
  var _useReducer = (0, _react.useReducer)(reducer, _objectSpread(_objectSpread({}, initState), {}, {
111
129
  url: (0, _url2.normalizeUrl)(initUrl) || '',
112
130
  displayText: initDisplayText || ''
@@ -119,17 +137,23 @@ function LinkPicker(_ref) {
119
137
  selectedIndex = state.selectedIndex,
120
138
  url = state.url,
121
139
  displayText = state.displayText,
122
- invalidUrl = state.invalidUrl;
123
- var isEditing = !!initUrl;
140
+ invalidUrl = state.invalidUrl,
141
+ activeTab = state.activeTab;
124
142
  var intl = (0, _reactIntlNext.useIntl)();
143
+ var queryState = (0, _useSearchQuery.useSearchQuery)(state);
125
144
 
126
- var _usePlugins = (0, _usePlugins2.usePlugins)(state, plugins),
145
+ var _usePlugins = (0, _usePlugins2.usePlugins)(queryState, activeTab, plugins),
127
146
  items = _usePlugins.items,
128
147
  isLoading = _usePlugins.isLoading,
129
- isSelectedItem = _usePlugins.isSelectedItem,
130
148
  isActivePlugin = _usePlugins.isActivePlugin,
131
- tabs = _usePlugins.tabs;
149
+ tabs = _usePlugins.tabs,
150
+ error = _usePlugins.error,
151
+ retry = _usePlugins.retry,
152
+ errorFallback = _usePlugins.errorFallback;
132
153
 
154
+ var isEditing = !!initUrl;
155
+ var selectedItem = items === null || items === void 0 ? void 0 : items[selectedIndex];
156
+ var isSelectedItem = (selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.url) === url;
133
157
  (0, _react.useLayoutEffect)(function () {
134
158
  if (onContentResize) {
135
159
  onContentResize();
@@ -183,15 +207,15 @@ function LinkPicker(_ref) {
183
207
  dispatch((0, _defineProperty2.default)({}, field, ''));
184
208
  }, []);
185
209
  var handleMouseEnterResultItem = (0, _react.useCallback)(function (objectId) {
186
- var index = findIndex(items, function (item) {
210
+ var index = items === null || items === void 0 ? void 0 : items.findIndex(function (item) {
187
211
  return item.objectId === objectId;
188
212
  });
189
213
  dispatch({
190
- activeIndex: index
214
+ activeIndex: index !== null && index !== void 0 ? index : -1
191
215
  });
192
216
  }, [items]);
193
217
  var handleMouseLeaveResultItem = (0, _react.useCallback)(function (objectId) {
194
- var index = findIndex(items, function (item) {
218
+ var index = items === null || items === void 0 ? void 0 : items.findIndex(function (item) {
195
219
  return item.objectId === objectId;
196
220
  }); // This is to avoid updating index that was set by other mouseenter event
197
221
 
@@ -202,6 +226,8 @@ function LinkPicker(_ref) {
202
226
  }
203
227
  }, [activeIndex, items]);
204
228
  var handleInsert = (0, _react.useCallback)(function (url, title, inputType) {
229
+ var event = createAnalyticsEvent((0, _analytics.default)('form.submitted.linkPicker', {}));
230
+ event.fire(_constants.ANALYTICS_CHANNEL);
205
231
  onSubmit(_objectSpread({
206
232
  url: url,
207
233
  displayText: displayText || null,
@@ -212,22 +238,23 @@ function LinkPicker(_ref) {
212
238
  }, inputType === 'manual' ? {
213
239
  rawUrl: state.url
214
240
  } : {}));
215
- }, [displayText, onSubmit, state.url]);
241
+ }, [displayText, onSubmit, state.url, createAnalyticsEvent]);
216
242
  var handleSelected = (0, _react.useCallback)(function (objectId) {
217
- var selectedItem = items.find(function (item) {
243
+ var selectedItem = items === null || items === void 0 ? void 0 : items.find(function (item) {
218
244
  return item.objectId === objectId;
219
245
  });
220
246
 
221
247
  if (selectedItem) {
222
248
  var _url = selectedItem.url,
223
249
  name = selectedItem.name;
250
+ dispatchEvent(new Event('submit'));
224
251
  handleInsert(_url, name, 'typeAhead');
225
252
  }
226
253
  }, [handleInsert, items]);
227
- var handleSubmit = (0, _react.useCallback)(function () {
228
- var selectedItem = items[selectedIndex];
254
+ var handleSubmit = (0, _react.useCallback)(function (event) {
255
+ event.preventDefault();
229
256
 
230
- if (isSelectedItem) {
257
+ if (isSelectedItem && selectedItem) {
231
258
  return handleInsert(selectedItem.url, selectedItem.name, 'typeAhead');
232
259
  }
233
260
 
@@ -240,18 +267,18 @@ function LinkPicker(_ref) {
240
267
  return dispatch({
241
268
  invalidUrl: true
242
269
  });
243
- }, [handleInsert, isSelectedItem, items, selectedIndex, url]);
270
+ }, [handleInsert, isSelectedItem, selectedItem, url]);
244
271
  var linkPlaceHolder = isActivePlugin ? _messages.messages.placeholder : _messages.messages.linkPlaceholder;
245
- var linkListTitle = url ? _messages.messages.titleResults : _messages.messages.titleRecentlyViewed;
272
+ var linkListTitle = (queryState === null || queryState === void 0 ? void 0 : (_queryState$query = queryState.query) === null || _queryState$query === void 0 ? void 0 : _queryState$query.length) !== 0 ? _messages.messages.titleResults : _messages.messages.titleRecentlyViewed;
246
273
  var insertButtonMsg = isEditing ? _messages.messages.saveButton : _messages.messages.insertButton;
247
- var noResults = isActivePlugin && !isLoading && !items.length && !(0, _url2.isSafeUrl)(url);
274
+ var noResults = (items === null || items === void 0 ? void 0 : items.length) === 0 && !error;
248
275
  var screenReaderDescriptionId = 'search-recent-links-field-description';
249
276
  var linkSearchListId = 'link-picker-search-list';
250
277
  var ariaActiveDescendant = selectedIndex > -1 ? "link-search-list-item-".concat(selectedIndex) : ''; // Added workaround with a screen reader Announcer specifically for VoiceOver + Safari
251
278
  // as the Aria design pattern for combobox does not work in this case
252
279
  // for details: https://a11y-internal.atlassian.net/browse/AK-740
253
280
 
254
- var screenReaderText = _browser.browser.safari && getScreenReaderText(items, selectedIndex, intl);
281
+ var screenReaderText = _browser.browser.safari && getScreenReaderText(items !== null && items !== void 0 ? items : [], selectedIndex, intl);
255
282
  var searchIcon = isActivePlugin && (0, _react2.jsx)("span", {
256
283
  css: _styled.searchIconStyles,
257
284
  "data-testid": testIds.searchIcon
@@ -259,9 +286,10 @@ function LinkPicker(_ref) {
259
286
  size: "medium",
260
287
  label: ''
261
288
  }));
262
- return (0, _react2.jsx)("div", {
289
+ return (0, _react2.jsx)("form", {
263
290
  "data-testid": testIds.linkPicker,
264
- css: _styled.rootContainerStyles
291
+ css: _styled.rootContainerStyles,
292
+ onSubmit: handleSubmit
265
293
  }, screenReaderText && (0, _react2.jsx)(_announcer.default, {
266
294
  ariaLive: "assertive",
267
295
  text: screenReaderText,
@@ -287,7 +315,6 @@ function LinkPicker(_ref) {
287
315
  "aria-describedby": screenReaderDescriptionId,
288
316
  error: invalidUrl ? intl.formatMessage(_messages.messages.linkInvalid) : null,
289
317
  onClear: handleClear,
290
- onSubmit: handleSubmit,
291
318
  onKeyDown: handleKeyDown,
292
319
  onChange: handleChangeUrl
293
320
  }), (0, _react2.jsx)(_textInput.default, {
@@ -300,10 +327,9 @@ function LinkPicker(_ref) {
300
327
  clearLabel: intl.formatMessage(_messages.messages.clearText),
301
328
  "aria-label": intl.formatMessage(_messages.messages.linkAriaLabel),
302
329
  onClear: handleClear,
303
- onSubmit: handleSubmit,
304
330
  onKeyDown: handleKeyDown,
305
331
  onChange: handleChangeText
306
- }), tabs.length > 0 && (0, _react2.jsx)("div", {
332
+ }), queryState && (0, _react2.jsx)(_react.Fragment, null, tabs.length > 0 && (0, _react2.jsx)("div", {
307
333
  css: _styled.tabsWrapperStyles
308
334
  }, (0, _react2.jsx)(_tabs.default, {
309
335
  id: testIds.tabList,
@@ -321,7 +347,7 @@ function LinkPicker(_ref) {
321
347
  key: tab.tabTitle,
322
348
  testId: testIds.tabItem
323
349
  }, tab.tabTitle);
324
- })))), !!items.length && (0, _react2.jsx)("div", {
350
+ })))), !!(items !== null && items !== void 0 && items.length) && (0, _react2.jsx)("div", {
325
351
  css: _styled.listTitleStyles,
326
352
  id: testIds.resultListTitle,
327
353
  "data-testid": testIds.resultListTitle
@@ -329,7 +355,7 @@ function LinkPicker(_ref) {
329
355
  id: "fabric.smartcard.linkpicker.suggested.results"
330
356
  }, url && (0, _react2.jsx)(_reactIntlNext.FormattedMessage, (0, _extends2.default)({}, _messages.messages.searchLinkResults, {
331
357
  values: {
332
- count: items.length
358
+ count: (_items$length = items === null || items === void 0 ? void 0 : items.length) !== null && _items$length !== void 0 ? _items$length : 0
333
359
  },
334
360
  "aria-live": "polite",
335
361
  "aria-atomic": "true"
@@ -338,18 +364,34 @@ function LinkPicker(_ref) {
338
364
  ariaControls: "fabric.smartcard.linkpicker.suggested.results",
339
365
  id: linkSearchListId,
340
366
  role: "listbox",
341
- items: items,
367
+ items: items !== null && items !== void 0 ? items : [],
342
368
  isLoading: isLoading,
343
369
  selectedIndex: selectedIndex,
344
370
  activeIndex: activeIndex,
345
371
  onSelect: handleSelected,
346
372
  onMouseEnter: handleMouseEnterResultItem,
347
373
  onMouseLeave: handleMouseLeaveResultItem
348
- }), noResults && (0, _react2.jsx)(_linkSearchNoResults.default, {
374
+ }), error && ((_errorFallback = errorFallback === null || errorFallback === void 0 ? void 0 : errorFallback(error, retry)) !== null && _errorFallback !== void 0 ? _errorFallback : (0, _react2.jsx)(_linkSearchError.default, {
375
+ testId: testIds.searchError,
376
+ header: intl.formatMessage(_messages.messages.searchErrorHeader),
377
+ description: (0, _react2.jsx)(_reactIntlNext.FormattedMessage, (0, _extends2.default)({}, _messages.messages.searchErrorDescription, {
378
+ values: {
379
+ a: function a(label) {
380
+ return (0, _react2.jsx)(_button.default, {
381
+ appearance: "link",
382
+ spacing: "none",
383
+ href: CONTACT_SUPPORT_LINK,
384
+ target: "_blank",
385
+ rel: "noopener noreferrer"
386
+ }, label);
387
+ }
388
+ }
389
+ }))
390
+ })), noResults && (0, _react2.jsx)(_linkSearchNoResults.default, {
349
391
  testId: testIds.emptyResultPage,
350
392
  header: intl.formatMessage(_messages.messages.noResults),
351
393
  description: intl.formatMessage(_messages.messages.noResultsDescription)
352
- }), (0, _react2.jsx)(_form.FormFooter, {
394
+ })), (0, _react2.jsx)(_form.FormFooter, {
353
395
  align: "end"
354
396
  }, (0, _react2.jsx)(_button.ButtonGroup, null, (0, _react2.jsx)(_button.default, {
355
397
  appearance: "default",
@@ -358,7 +400,6 @@ function LinkPicker(_ref) {
358
400
  }, intl.formatMessage(_messages.messages.cancelButton)), (0, _react2.jsx)(_button.default, {
359
401
  type: "submit",
360
402
  appearance: "primary",
361
- onClick: handleSubmit,
362
403
  testId: testIds.insertButton
363
404
  }, intl.formatMessage(insertButtonMsg)))));
364
405
  }
@@ -377,17 +418,4 @@ function getScreenReaderText(items, selectedIndex, intl) {
377
418
  var formattedDate = [date === null || date === void 0 ? void 0 : date.pageAction, date === null || date === void 0 ? void 0 : date.dateString, date === null || date === void 0 ? void 0 : date.timeSince].filter(Boolean).join(' ');
378
419
  return [name, container, formattedDate].filter(Boolean).join(', ');
379
420
  }
380
- }
381
-
382
- function findIndex(array, predicate) {
383
- var index = -1;
384
- array.some(function (item, i) {
385
- if (predicate(item)) {
386
- index = i;
387
- return true;
388
- }
389
-
390
- return false;
391
- });
392
- return index;
393
421
  }
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.default = void 0;
9
+
10
+ var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
11
+
12
+ var _react = _interopRequireDefault(require("react"));
13
+
14
+ var _emptyState = _interopRequireDefault(require("@atlaskit/empty-state"));
15
+
16
+ var _genericErrorSvg = _interopRequireDefault(require("../../../common/generic-error-svg"));
17
+
18
+ var LinkSearchError = function LinkSearchError(props) {
19
+ return /*#__PURE__*/_react.default.createElement(_emptyState.default, (0, _extends2.default)({}, props, {
20
+ renderImage: function renderImage() {
21
+ return /*#__PURE__*/_react.default.createElement(_genericErrorSvg.default, null);
22
+ }
23
+ }));
24
+ };
25
+
26
+ var _default = LinkSearchError;
27
+ exports.default = _default;
@@ -112,6 +112,16 @@ var messages = (0, _reactIntlNext.defineMessages)({
112
112
  id: 'fabric.linkPicker.button.save',
113
113
  defaultMessage: 'Save',
114
114
  description: 'Button to save edited link'
115
+ },
116
+ searchErrorHeader: {
117
+ id: 'fabric.linkPicker.search.error.heading',
118
+ defaultMessage: 'We’re having trouble loading data.',
119
+ description: 'Heading message shown when a search throws an error'
120
+ },
121
+ searchErrorDescription: {
122
+ id: 'fabric.linkPicker.search.error.description',
123
+ defaultMessage: 'Refresh the page, or contact <a>Atlassian Support</a> if this keeps happening.',
124
+ description: 'Describes possible actions when search throws an error'
115
125
  }
116
126
  });
117
127
  exports.messages = messages;