@atlaskit/link-picker 1.3.0 → 1.5.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.
@@ -1,26 +1,15 @@
1
- import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
2
- import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
3
- import _createClass from "@babel/runtime/helpers/createClass";
4
- import _assertThisInitialized from "@babel/runtime/helpers/assertThisInitialized";
5
- import _inherits from "@babel/runtime/helpers/inherits";
6
- import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn";
7
- import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";
1
+ import _extends from "@babel/runtime/helpers/extends";
2
+ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
8
3
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
9
4
 
10
5
  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; }
11
6
 
12
7
  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) { _defineProperty(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; }
13
8
 
14
- import _regeneratorRuntime from "@babel/runtime/regenerator";
15
-
16
- 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); }; }
17
-
18
- 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; } }
19
-
20
9
  /** @jsx jsx */
21
- import { PureComponent } from 'react';
10
+ import { useCallback, useReducer } from 'react';
22
11
  import { jsx } from '@emotion/react';
23
- import { injectIntl } from 'react-intl-next';
12
+ import { useIntl, FormattedMessage } from 'react-intl-next';
24
13
  import { messages } from './messages';
25
14
  import PanelTextInput from './text-input';
26
15
  import LinkSearchList from './link-search-list';
@@ -32,536 +21,318 @@ import Announcer from './/announcer';
32
21
  import Button, { ButtonGroup } from '@atlaskit/button';
33
22
  import { FormFooter } from '@atlaskit/form';
34
23
  import EditorSearchIcon from '@atlaskit/icon/glyph/editor/search';
24
+ import Tabs, { Tab, TabList } from '@atlaskit/tabs';
35
25
  import VisuallyHidden from '@atlaskit/visually-hidden';
36
26
  import LinkSearchNoResults from './link-search-no-results';
27
+ import { usePlugins } from '../../services/use-plugins';
37
28
  export var RECENT_SEARCH_LIST_SIZE = 5;
29
+ export var testIds = {
30
+ linkPicker: 'link-picker',
31
+ urlInputField: 'link-url',
32
+ textInputField: 'link-text',
33
+ searchIcon: 'link-picker-search-icon',
34
+ insertButton: 'link-picker-insert-button',
35
+ cancelButton: 'link-picker-cancel-button',
36
+ clearUrlButton: 'clear-text',
37
+ resultListTitle: 'link-picker-list-title',
38
+ emptyResultPage: 'link-search-no-results',
39
+ searchResultList: 'link-search-list',
40
+ searchResultItem: 'link-search-list-item',
41
+ searchResultLoadingIndicator: 'link-picker.results-loading-indicator',
42
+ urlError: 'link-error',
43
+ tabList: 'link-picker-tabs',
44
+ tabItem: 'link-picker-tab'
45
+ };
46
+ var initState = {
47
+ url: '',
48
+ displayText: '',
49
+ activeIndex: -1,
50
+ selectedIndex: -1,
51
+ invalidUrl: false,
52
+ activeTab: 0
53
+ };
54
+
55
+ function reducer(state, payload) {
56
+ if (payload.url && state.url !== payload.url) {
57
+ return _objectSpread(_objectSpread({}, state), {}, {
58
+ invalidUrl: false,
59
+ selectedIndex: isSafeUrl(payload.url) && payload.url.length ? -1 : state.selectedIndex
60
+ }, payload);
61
+ }
38
62
 
39
- var LinkPicker = /*#__PURE__*/function (_PureComponent) {
40
- _inherits(LinkPicker, _PureComponent);
41
-
42
- var _super = _createSuper(LinkPicker);
43
-
44
- function LinkPicker(props) {
45
- var _this;
46
-
47
- _classCallCheck(this, LinkPicker);
48
-
49
- _this = _super.call(this, props);
50
-
51
- _defineProperty(_assertThisInitialized(_this), "queryVersion", 0);
52
-
53
- _defineProperty(_assertThisInitialized(_this), "updateInput", /*#__PURE__*/function () {
54
- var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(input) {
55
- return _regeneratorRuntime.wrap(function _callee$(_context) {
56
- while (1) {
57
- switch (_context.prev = _context.next) {
58
- case 0:
59
- if (!(input.length && isSafeUrl(input))) {
60
- _context.next = 2;
61
- break;
62
- }
63
-
64
- return _context.abrupt("return", _this.setState({
65
- url: input,
66
- selectedIndex: -1,
67
- items: [],
68
- isLoading: false,
69
- invalidUrl: null
70
- }));
71
-
72
- case 2:
73
- return _context.abrupt("return", _this.setState({
74
- url: input,
75
- // Unset selection on any input change
76
- selectedIndex: -1,
77
- invalidUrl: null
78
- }, function () {
79
- _this.updateResults();
80
- }));
81
-
82
- case 3:
83
- case "end":
84
- return _context.stop();
85
- }
86
- }
87
- }, _callee);
88
- }));
89
-
90
- return function (_x) {
91
- return _ref.apply(this, arguments);
92
- };
93
- }());
94
-
95
- _defineProperty(_assertThisInitialized(_this), "createClearHandler", function (field) {
96
- return function () {
97
- switch (field) {
98
- case 'url':
99
- {
100
- _this.updateInput('');
101
-
102
- break;
103
- }
104
-
105
- case 'displayText':
106
- {
107
- _this.setState(_defineProperty({}, field, ''));
108
- }
109
- }
110
- };
111
- });
112
-
113
- _defineProperty(_assertThisInitialized(_this), "getScreenReaderText", function () {
114
- var intl = _this.props.intl;
115
- var _this$state = _this.state,
116
- items = _this$state.items,
117
- selectedIndex = _this$state.selectedIndex;
118
-
119
- if (items.length && selectedIndex > -1) {
120
- var _items$selectedIndex = items[selectedIndex],
121
- name = _items$selectedIndex.name,
122
- container = _items$selectedIndex.container,
123
- lastUpdatedDate = _items$selectedIndex.lastUpdatedDate,
124
- lastViewedDate = _items$selectedIndex.lastViewedDate;
125
- var date = transformTimeStamp(intl, lastViewedDate, lastUpdatedDate);
126
- 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(' ');
127
- return [name, container, formattedDate].filter(Boolean).join(', ');
128
- }
129
- });
130
-
131
- _defineProperty(_assertThisInitialized(_this), "isUrlPopulatedWithSelectedItem", function () {
132
- /**
133
- * When we use ArrowKey to navigate through result items,
134
- * the URL field will be populated with the content of
135
- * selected item.
136
- * This function will check if the URL field is populated
137
- * with selected item.
138
- * It can be useful to detect whether we want to insert a
139
- * smartlink or a hyperlink with customized title
140
- */
141
- var _this$state2 = _this.state,
142
- items = _this$state2.items,
143
- selectedIndex = _this$state2.selectedIndex,
144
- url = _this$state2.url;
145
- var selectedItem = items[selectedIndex];
146
-
147
- if (selectedItem && selectedItem.url === url) {
148
- return true;
149
- }
63
+ return _objectSpread(_objectSpread({}, state), payload);
64
+ }
150
65
 
151
- return false;
66
+ function LinkPicker(_ref) {
67
+ var onSubmit = _ref.onSubmit,
68
+ onCancel = _ref.onCancel,
69
+ plugins = _ref.plugins,
70
+ initUrl = _ref.url,
71
+ initDisplayText = _ref.displayText;
72
+
73
+ var _useReducer = useReducer(reducer, _objectSpread(_objectSpread({}, initState), {}, {
74
+ url: normalizeUrl(initUrl) || '',
75
+ displayText: initDisplayText || ''
76
+ })),
77
+ _useReducer2 = _slicedToArray(_useReducer, 2),
78
+ state = _useReducer2[0],
79
+ dispatch = _useReducer2[1];
80
+
81
+ var activeIndex = state.activeIndex,
82
+ selectedIndex = state.selectedIndex,
83
+ url = state.url,
84
+ displayText = state.displayText,
85
+ invalidUrl = state.invalidUrl;
86
+ var isEditing = !!initUrl;
87
+ var intl = useIntl();
88
+
89
+ var _usePlugins = usePlugins(state, plugins),
90
+ items = _usePlugins.items,
91
+ isLoading = _usePlugins.isLoading,
92
+ isSelectedItem = _usePlugins.isSelectedItem,
93
+ isActivePlugin = _usePlugins.isActivePlugin,
94
+ tabs = _usePlugins.tabs;
95
+
96
+ var handleChangeUrl = useCallback(function (url) {
97
+ dispatch({
98
+ url: url
152
99
  });
153
-
154
- _defineProperty(_assertThisInitialized(_this), "handleSelected", function (objectId) {
155
- var items = _this.state.items;
156
- var selectedItem = items.find(function (item) {
157
- return item.objectId === objectId;
158
- });
159
-
160
- if (selectedItem) {
161
- var url = selectedItem.url,
162
- name = selectedItem.name;
163
-
164
- _this.handleInsert(url, name, 'typeAhead');
165
- }
100
+ }, []);
101
+ var handleChangeText = useCallback(function (displayText) {
102
+ dispatch({
103
+ displayText: displayText
166
104
  });
105
+ }, []);
106
+ var handleKeyDown = useCallback(function (event) {
107
+ var keyCode = event.keyCode;
108
+ var KEY_CODE_ARROW_DOWN = 40;
109
+ var KEY_CODE_ARROW_UP = 38;
110
+
111
+ if (!items || !items.length) {
112
+ return;
113
+ }
167
114
 
168
- _defineProperty(_assertThisInitialized(_this), "handleInsert", function (url, title, inputType) {
169
- var onSubmit = _this.props.onSubmit;
170
- var _this$state3 = _this.state,
171
- rawUrl = _this$state3.url,
172
- displayText = _this$state3.displayText;
115
+ var updatedIndex = activeIndex;
173
116
 
174
- if (onSubmit) {
175
- onSubmit(_objectSpread({
176
- url: url,
177
- displayText: displayText || null,
178
- title: title || null,
179
- meta: {
180
- inputMethod: inputType
181
- }
182
- }, inputType === 'manual' ? {
183
- rawUrl: rawUrl
184
- } : {}));
185
- }
186
- });
117
+ switch (keyCode) {
118
+ case KEY_CODE_ARROW_DOWN:
119
+ // down
120
+ event.preventDefault();
121
+ updatedIndex = (activeIndex + 1) % items.length;
122
+ break;
187
123
 
188
- _defineProperty(_assertThisInitialized(_this), "handleMouseEnterResultItem", function (objectId) {
189
- var items = _this.state.items;
190
- var index = findIndex(items, function (item) {
191
- return item.objectId === objectId;
192
- });
124
+ case KEY_CODE_ARROW_UP:
125
+ // up
126
+ event.preventDefault();
127
+ updatedIndex = activeIndex > 0 ? activeIndex - 1 : items.length - 1;
128
+ break;
129
+ }
193
130
 
194
- _this.setState({
195
- activeIndex: index
131
+ if ([KEY_CODE_ARROW_DOWN, KEY_CODE_ARROW_UP].includes(keyCode) && items[updatedIndex]) {
132
+ dispatch({
133
+ activeIndex: updatedIndex,
134
+ selectedIndex: updatedIndex,
135
+ url: items[updatedIndex].url,
136
+ invalidUrl: false
196
137
  });
138
+ }
139
+ }, [activeIndex, items]);
140
+ var handleClear = useCallback(function (field) {
141
+ dispatch(_defineProperty({}, field, ''));
142
+ }, []);
143
+ var handleMouseEnterResultItem = useCallback(function (objectId) {
144
+ var index = findIndex(items, function (item) {
145
+ return item.objectId === objectId;
197
146
  });
198
-
199
- _defineProperty(_assertThisInitialized(_this), "handleMouseLeaveResultItem", function (objectId) {
200
- var _this$state4 = _this.state,
201
- items = _this$state4.items,
202
- activeIndex = _this$state4.activeIndex;
203
- var index = findIndex(items, function (item) {
204
- return item.objectId === objectId;
205
- }); // This is to avoid updating index that was set by other mouseenter event
206
-
207
- if (activeIndex === index) {
208
- _this.setState({
209
- activeIndex: -1
210
- });
211
- }
147
+ dispatch({
148
+ activeIndex: index
212
149
  });
213
-
214
- _defineProperty(_assertThisInitialized(_this), "handleSubmit", function () {
215
- var _this$state5 = _this.state,
216
- url = _this$state5.url,
217
- selectedIndex = _this$state5.selectedIndex,
218
- items = _this$state5.items;
219
- var intl = _this.props.intl;
220
- var selectedItem = items[selectedIndex];
221
-
222
- if (_this.isUrlPopulatedWithSelectedItem()) {
223
- return _this.handleInsert(selectedItem.url, selectedItem.name, 'typeAhead');
224
- }
225
-
226
- var normalized = normalizeUrl(url);
227
-
228
- if (normalized) {
229
- return _this.handleInsert(normalized, null, 'manual');
230
- }
231
-
232
- return _this.setState({
233
- invalidUrl: intl.formatMessage(messages.linkInvalid)
150
+ }, [items]);
151
+ var handleMouseLeaveResultItem = useCallback(function (objectId) {
152
+ var index = findIndex(items, function (item) {
153
+ return item.objectId === objectId;
154
+ }); // This is to avoid updating index that was set by other mouseenter event
155
+
156
+ if (activeIndex === index) {
157
+ dispatch({
158
+ activeIndex: -1
234
159
  });
235
- });
236
-
237
- _defineProperty(_assertThisInitialized(_this), "handleKeyDown", function (event) {
238
- var _this$state6 = _this.state,
239
- items = _this$state6.items,
240
- activeIndex = _this$state6.activeIndex;
241
- var keyCode = event.keyCode;
242
- var KEY_CODE_ARROW_DOWN = 40;
243
- var KEY_CODE_ARROW_UP = 38;
244
-
245
- if (!items || !items.length) {
246
- return;
247
- }
248
-
249
- var updatedIndex = activeIndex;
250
-
251
- switch (keyCode) {
252
- case KEY_CODE_ARROW_DOWN:
253
- // down
254
- event.preventDefault();
255
- updatedIndex = (activeIndex + 1) % items.length;
256
- break;
257
-
258
- case KEY_CODE_ARROW_UP:
259
- // up
260
- event.preventDefault();
261
- updatedIndex = activeIndex > 0 ? activeIndex - 1 : items.length - 1;
262
- break;
263
- }
264
-
265
- if ([KEY_CODE_ARROW_DOWN, KEY_CODE_ARROW_UP].includes(keyCode) && items[updatedIndex]) {
266
- _this.setState({
267
- activeIndex: updatedIndex,
268
- selectedIndex: updatedIndex,
269
- url: items[updatedIndex].url,
270
- invalidUrl: null
271
- });
272
- }
273
- });
274
-
275
- _defineProperty(_assertThisInitialized(_this), "handleCancel", function () {
276
- var onCancel = _this.props.onCancel;
277
-
278
- if (onCancel) {
279
- onCancel();
160
+ }
161
+ }, [activeIndex, items]);
162
+ var handleInsert = useCallback(function (url, title, inputType) {
163
+ onSubmit(_objectSpread({
164
+ url: url,
165
+ displayText: displayText || null,
166
+ title: title || null,
167
+ meta: {
168
+ inputMethod: inputType
280
169
  }
170
+ }, inputType === 'manual' ? {
171
+ rawUrl: state.url
172
+ } : {}));
173
+ }, [displayText, onSubmit, state.url]);
174
+ var handleSelected = useCallback(function (objectId) {
175
+ var selectedItem = items.find(function (item) {
176
+ return item.objectId === objectId;
281
177
  });
282
178
 
283
- _defineProperty(_assertThisInitialized(_this), "updateTextInput", function (displayText) {
284
- _this.setState({
285
- displayText: displayText
286
- });
287
- });
288
-
289
- _this.state = {
290
- selectedIndex: -1,
291
- activeIndex: -1,
292
- isLoading: false,
293
- isEditing: !!props.url,
294
- url: normalizeUrl(props.url) || '',
295
- displayText: props.displayText || '',
296
- items: [],
297
- invalidUrl: null
298
- };
299
- /* Cache functions */
300
-
301
- _this.handleClearUrl = _this.createClearHandler('url');
302
- _this.handleClearDisplayText = _this.createClearHandler('displayText');
303
- return _this;
304
- }
305
-
306
- _createClass(LinkPicker, [{
307
- key: "componentDidMount",
308
- value: function componentDidMount() {
309
- this.loadInitialLinkSearchResult();
179
+ if (selectedItem) {
180
+ var _url = selectedItem.url,
181
+ name = selectedItem.name;
182
+ handleInsert(_url, name, 'typeAhead');
310
183
  }
311
- }, {
312
- key: "loadInitialLinkSearchResult",
313
- value: function loadInitialLinkSearchResult() {
314
- var url = this.state.url;
184
+ }, [handleInsert, items]);
185
+ var handleSubmit = useCallback(function () {
186
+ var selectedItem = items[selectedIndex];
315
187
 
316
- if (!url) {
317
- this.updateResults();
318
- }
188
+ if (isSelectedItem) {
189
+ return handleInsert(selectedItem.url, selectedItem.name, 'typeAhead');
319
190
  }
320
- }, {
321
- key: "getActivePlugin",
322
- value: function getActivePlugin() {
323
- if (!this.props.plugins || this.props.plugins.length === 0) {
324
- return null;
325
- }
326
-
327
- return this.props.plugins[0];
328
- }
329
- /**
330
- * Interface between link picker and plugins to update results
331
- */
332
-
333
- }, {
334
- key: "updateResults",
335
- value: function () {
336
- var _updateResults = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
337
- var queryVersion, activePlugin, updates, done, value, _result$done, result;
338
-
339
- return _regeneratorRuntime.wrap(function _callee2$(_context2) {
340
- while (1) {
341
- switch (_context2.prev = _context2.next) {
342
- case 0:
343
- queryVersion = ++this.queryVersion;
344
- activePlugin = this.getActivePlugin();
345
-
346
- if (activePlugin) {
347
- _context2.next = 4;
348
- break;
349
- }
350
-
351
- return _context2.abrupt("return");
352
-
353
- case 4:
354
- updates = activePlugin.resolve({
355
- query: this.state.url
356
- });
357
- this.setState({
358
- isLoading: true,
359
- items: []
360
- });
361
- _context2.prev = 6;
362
-
363
- case 7:
364
- if (!(queryVersion === this.queryVersion)) {
365
- _context2.next = 29;
366
- break;
367
- }
368
-
369
- done = false;
370
- value = void 0;
371
191
 
372
- if (!(updates instanceof Promise)) {
373
- _context2.next = 17;
374
- break;
375
- }
192
+ var normalized = normalizeUrl(url);
376
193
 
377
- done = true;
378
- _context2.next = 14;
379
- return updates;
380
-
381
- case 14:
382
- value = _context2.sent;
383
- _context2.next = 22;
384
- break;
385
-
386
- case 17:
387
- _context2.next = 19;
388
- return updates.next();
389
-
390
- case 19:
391
- result = _context2.sent;
392
- done = (_result$done = result.done) !== null && _result$done !== void 0 ? _result$done : false;
393
- value = result.value;
394
-
395
- case 22:
396
- if (!(queryVersion !== this.queryVersion)) {
397
- _context2.next = 24;
398
- break;
399
- }
400
-
401
- return _context2.abrupt("return");
402
-
403
- case 24:
404
- this.setState({
405
- items: limit(value.data),
406
- isLoading: !done
407
- });
408
-
409
- if (!done) {
410
- _context2.next = 27;
411
- break;
412
- }
413
-
414
- return _context2.abrupt("return");
415
-
416
- case 27:
417
- _context2.next = 7;
418
- break;
419
-
420
- case 29:
421
- _context2.next = 34;
422
- break;
423
-
424
- case 31:
425
- _context2.prev = 31;
426
- _context2.t0 = _context2["catch"](6);
427
- this.setState({
428
- isLoading: false
429
- });
430
-
431
- case 34:
432
- case "end":
433
- return _context2.stop();
434
- }
435
- }
436
- }, _callee2, this, [[6, 31]]);
437
- }));
438
-
439
- function updateResults() {
440
- return _updateResults.apply(this, arguments);
441
- }
442
-
443
- return updateResults;
444
- }()
445
- }, {
446
- key: "render",
447
- value: function render() {
448
- var _this$state7 = this.state,
449
- items = _this$state7.items,
450
- isLoading = _this$state7.isLoading,
451
- isEditing = _this$state7.isEditing,
452
- activeIndex = _this$state7.activeIndex,
453
- selectedIndex = _this$state7.selectedIndex,
454
- url = _this$state7.url,
455
- displayText = _this$state7.displayText;
456
- var formatMessage = this.props.intl.formatMessage;
457
- var activePlugin = this.getActivePlugin();
458
- var linkPlaceHolder = formatMessage(activePlugin ? messages.placeholder : messages.linkPlaceholder);
459
- var linkLabel = formatMessage(messages.linkLabel);
460
- var linkTextLabel = formatMessage(messages.linkTextLabel);
461
- var linkTextPlaceHolder = formatMessage(messages.linkTextPlaceholder);
462
- var screenReaderDescriptionId = 'search-recent-links-field-description';
463
- var linkSearchListId = 'link-picker-search-list';
464
- var ariaActiveDescendant = selectedIndex > -1 ? "link-search-list-item-".concat(selectedIndex) : ''; // Added workaround with a screen reader Announcer specifically for VoiceOver + Safari
465
- // as the Aria design pattern for combobox does not work in this case
466
- // for details: https://a11y-internal.atlassian.net/browse/AK-740
194
+ if (normalized) {
195
+ return handleInsert(normalized, null, 'manual');
196
+ }
467
197
 
468
- var screenReaderText = browser.safari && this.getScreenReaderText();
469
- var searchIcon = activePlugin && jsx("span", {
470
- css: searchIconStyles,
471
- "data-testid": "link-picker-search-icon"
472
- }, jsx(EditorSearchIcon, {
473
- size: "medium",
474
- label: ''
475
- }));
476
- var noResults = activePlugin && !isLoading && !items.length && !isSafeUrl(url);
477
- return jsx("div", {
478
- "data-testid": "link-picker",
479
- css: rootContainerStyles
480
- }, screenReaderText && jsx(Announcer, {
481
- ariaLive: "assertive",
482
- text: screenReaderText,
483
- ariaRelevant: "additions",
484
- delay: 250
485
- }), jsx(VisuallyHidden, null, jsx("span", {
486
- "aria-hidden": "true",
487
- id: screenReaderDescriptionId
488
- }, formatMessage(messages.searchLinkAriaDescription))), jsx(PanelTextInput, {
489
- name: "link",
490
- testId: "link-url",
491
- role: "combobox",
492
- label: linkLabel,
493
- placeholder: linkPlaceHolder,
494
- value: url,
495
- autoFocus: true,
496
- autoComplete: "off",
497
- elemBeforeInput: searchIcon,
498
- onSubmit: this.handleSubmit,
499
- onChange: this.updateInput,
500
- onKeyDown: this.handleKeyDown,
501
- onClear: this.handleClearUrl,
502
- error: this.state.invalidUrl,
503
- clearLabel: formatMessage(messages.clearLink),
504
- "aria-controls": linkSearchListId,
505
- "aria-autocomplete": "list",
506
- "aria-activedescendant": ariaActiveDescendant,
507
- "aria-describedby": screenReaderDescriptionId,
508
- "aria-expanded": true
509
- }), jsx(PanelTextInput, {
510
- name: "link-text",
511
- testId: "link-text",
512
- autoComplete: "off",
513
- label: linkTextLabel,
514
- placeholder: linkTextPlaceHolder,
515
- "aria-label": formatMessage(messages.linkAriaLabel),
516
- value: displayText,
517
- onSubmit: this.handleSubmit,
518
- onKeyDown: this.handleKeyDown,
519
- onChange: this.updateTextInput,
520
- onClear: this.handleClearDisplayText,
521
- clearLabel: formatMessage(messages.clearText)
522
- }), !!items.length && jsx("div", {
523
- css: listTitleStyles,
524
- id: "link-picker-list-title",
525
- "data-testid": "link-picker-list-title"
526
- }, formatMessage(this.state.url ? messages.titleResults : messages.titleRecentlyViewed)), jsx(VisuallyHidden, null, jsx("span", {
527
- "aria-live": "polite",
528
- "aria-atomic": "true",
529
- id: "fabric.smartcard.linkpicker.suggested.results"
530
- }, url && formatMessage(messages.searchLinkResults, {
531
- count: items.length
532
- }))), jsx(LinkSearchList, {
533
- ariaLabelledBy: "link-picker-list-title",
534
- ariaControls: "fabric.smartcard.linkpicker.suggested.results",
535
- id: linkSearchListId,
536
- role: "listbox",
537
- items: items,
538
- isLoading: isLoading,
539
- selectedIndex: selectedIndex,
540
- activeIndex: activeIndex,
541
- onSelect: this.handleSelected,
542
- onMouseEnter: this.handleMouseEnterResultItem,
543
- onMouseLeave: this.handleMouseLeaveResultItem
544
- }), noResults && jsx(LinkSearchNoResults, {
545
- testId: "link-search-no-results",
546
- header: formatMessage(messages.noResults),
547
- description: formatMessage(messages.noResultsDescription)
548
- }), jsx(FormFooter, {
549
- align: "end"
550
- }, jsx(ButtonGroup, null, jsx(Button, {
551
- appearance: "default",
552
- onClick: this.handleCancel,
553
- testId: "link-picker-cancel-button"
554
- }, formatMessage(messages.cancelButton)), jsx(Button, {
555
- type: "submit",
556
- appearance: "primary",
557
- onClick: this.handleSubmit,
558
- testId: "link-picker-insert-button"
559
- }, formatMessage(isEditing ? messages.saveButton : messages.insertButton)))));
198
+ return dispatch({
199
+ invalidUrl: true
200
+ });
201
+ }, [handleInsert, isSelectedItem, items, selectedIndex, url]);
202
+ var linkPlaceHolder = isActivePlugin ? messages.placeholder : messages.linkPlaceholder;
203
+ var linkListTitle = url ? messages.titleResults : messages.titleRecentlyViewed;
204
+ var insertButtonMsg = isEditing ? messages.saveButton : messages.insertButton;
205
+ var noResults = isActivePlugin && !isLoading && !items.length && !isSafeUrl(url);
206
+ var screenReaderDescriptionId = 'search-recent-links-field-description';
207
+ var linkSearchListId = 'link-picker-search-list';
208
+ var ariaActiveDescendant = selectedIndex > -1 ? "link-search-list-item-".concat(selectedIndex) : ''; // Added workaround with a screen reader Announcer specifically for VoiceOver + Safari
209
+ // as the Aria design pattern for combobox does not work in this case
210
+ // for details: https://a11y-internal.atlassian.net/browse/AK-740
211
+
212
+ var screenReaderText = browser.safari && getScreenReaderText(items, selectedIndex, intl);
213
+ var searchIcon = isActivePlugin && jsx("span", {
214
+ css: searchIconStyles,
215
+ "data-testid": testIds.searchIcon
216
+ }, jsx(EditorSearchIcon, {
217
+ size: "medium",
218
+ label: ''
219
+ }));
220
+ return jsx("div", {
221
+ "data-testid": testIds.linkPicker,
222
+ css: rootContainerStyles
223
+ }, screenReaderText && jsx(Announcer, {
224
+ ariaLive: "assertive",
225
+ text: screenReaderText,
226
+ ariaRelevant: "additions",
227
+ delay: 250
228
+ }), jsx(VisuallyHidden, {
229
+ id: screenReaderDescriptionId
230
+ }, jsx(FormattedMessage, messages.searchLinkAriaDescription)), jsx(PanelTextInput, {
231
+ role: "combobox",
232
+ autoComplete: "off",
233
+ name: "url",
234
+ testId: testIds.urlInputField,
235
+ label: intl.formatMessage(messages.linkLabel),
236
+ placeholder: intl.formatMessage(linkPlaceHolder),
237
+ value: url,
238
+ autoFocus: true,
239
+ elemBeforeInput: searchIcon,
240
+ clearLabel: intl.formatMessage(messages.clearLink),
241
+ "aria-expanded": true,
242
+ "aria-autocomplete": "list",
243
+ "aria-controls": linkSearchListId,
244
+ "aria-activedescendant": ariaActiveDescendant,
245
+ "aria-describedby": screenReaderDescriptionId,
246
+ error: invalidUrl ? intl.formatMessage(messages.linkInvalid) : null,
247
+ onClear: handleClear,
248
+ onSubmit: handleSubmit,
249
+ onKeyDown: handleKeyDown,
250
+ onChange: handleChangeUrl
251
+ }), jsx(PanelTextInput, {
252
+ autoComplete: "off",
253
+ name: "displayText",
254
+ testId: testIds.textInputField,
255
+ value: displayText,
256
+ label: intl.formatMessage(messages.linkTextLabel),
257
+ placeholder: intl.formatMessage(messages.linkTextPlaceholder),
258
+ clearLabel: intl.formatMessage(messages.clearText),
259
+ "aria-label": intl.formatMessage(messages.linkAriaLabel),
260
+ onClear: handleClear,
261
+ onSubmit: handleSubmit,
262
+ onKeyDown: handleKeyDown,
263
+ onChange: handleChangeText
264
+ }), tabs.length > 0 && jsx(Tabs, {
265
+ id: testIds.tabList,
266
+ testId: testIds.tabList,
267
+ onChange: function onChange(activeTab) {
268
+ return dispatch({
269
+ selectedIndex: -1,
270
+ activeIndex: -1,
271
+ invalidUrl: false,
272
+ activeTab: activeTab
273
+ });
560
274
  }
561
- }]);
275
+ }, jsx(TabList, null, tabs.map(function (tab) {
276
+ return jsx(Tab, {
277
+ key: tab.tabTitle,
278
+ testId: testIds.tabItem
279
+ }, tab.tabTitle);
280
+ }))), !!items.length && jsx("div", {
281
+ css: listTitleStyles,
282
+ id: testIds.resultListTitle,
283
+ "data-testid": testIds.resultListTitle
284
+ }, jsx(FormattedMessage, linkListTitle)), jsx(VisuallyHidden, {
285
+ id: "fabric.smartcard.linkpicker.suggested.results"
286
+ }, url && jsx(FormattedMessage, _extends({}, messages.searchLinkResults, {
287
+ values: {
288
+ count: items.length
289
+ },
290
+ "aria-live": "polite",
291
+ "aria-atomic": "true"
292
+ }))), jsx(LinkSearchList, {
293
+ ariaLabelledBy: testIds.resultListTitle,
294
+ ariaControls: "fabric.smartcard.linkpicker.suggested.results",
295
+ id: linkSearchListId,
296
+ role: "listbox",
297
+ items: items,
298
+ isLoading: isLoading,
299
+ selectedIndex: selectedIndex,
300
+ activeIndex: activeIndex,
301
+ onSelect: handleSelected,
302
+ onMouseEnter: handleMouseEnterResultItem,
303
+ onMouseLeave: handleMouseLeaveResultItem
304
+ }), noResults && jsx(LinkSearchNoResults, {
305
+ testId: testIds.emptyResultPage,
306
+ header: intl.formatMessage(messages.noResults),
307
+ description: intl.formatMessage(messages.noResultsDescription)
308
+ }), jsx(FormFooter, {
309
+ align: "end"
310
+ }, jsx(ButtonGroup, null, jsx(Button, {
311
+ appearance: "default",
312
+ onClick: onCancel,
313
+ testId: testIds.cancelButton
314
+ }, intl.formatMessage(messages.cancelButton)), jsx(Button, {
315
+ type: "submit",
316
+ appearance: "primary",
317
+ onClick: handleSubmit,
318
+ testId: testIds.insertButton
319
+ }, intl.formatMessage(insertButtonMsg)))));
320
+ }
562
321
 
563
- return LinkPicker;
564
- }(PureComponent);
322
+ export default LinkPicker;
323
+
324
+ function getScreenReaderText(items, selectedIndex, intl) {
325
+ if (items.length && selectedIndex > -1) {
326
+ var _items$selectedIndex = items[selectedIndex],
327
+ name = _items$selectedIndex.name,
328
+ container = _items$selectedIndex.container,
329
+ lastUpdatedDate = _items$selectedIndex.lastUpdatedDate,
330
+ lastViewedDate = _items$selectedIndex.lastViewedDate;
331
+ var date = transformTimeStamp(intl, lastViewedDate, lastUpdatedDate);
332
+ 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(' ');
333
+ return [name, container, formattedDate].filter(Boolean).join(', ');
334
+ }
335
+ }
565
336
 
566
337
  function findIndex(array, predicate) {
567
338
  var index = -1;
@@ -574,10 +345,4 @@ function findIndex(array, predicate) {
574
345
  return false;
575
346
  });
576
347
  return index;
577
- }
578
-
579
- function limit(items) {
580
- return items.slice(0, RECENT_SEARCH_LIST_SIZE);
581
- }
582
-
583
- export default injectIntl(LinkPicker);
348
+ }