@atlaskit/link-picker 1.8.2 → 1.8.5

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 (91) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/cjs/analytics.codegen.js +1 -1
  3. package/dist/cjs/{ui/link-picker → common/utils}/url.js +0 -0
  4. package/dist/cjs/controllers/use-fix-height/index.js +27 -0
  5. package/dist/cjs/services/use-plugins/index.js +48 -90
  6. package/dist/cjs/services/use-plugins/reducer.js +64 -0
  7. package/dist/cjs/services/use-plugins/utils.js +134 -0
  8. package/dist/cjs/services/use-search-query/index.js +1 -1
  9. package/dist/cjs/services/with-link-picker-analytics/index.js +33 -0
  10. package/dist/cjs/ui/link-picker/form-footer/index.js +76 -0
  11. package/dist/cjs/ui/link-picker/form-footer/styled.js +17 -0
  12. package/dist/cjs/ui/link-picker/index.js +33 -75
  13. package/dist/cjs/ui/link-picker/link-search-error/index.js +47 -6
  14. package/dist/cjs/ui/link-picker/link-search-list/index.js +89 -20
  15. package/dist/cjs/ui/link-picker/link-search-list/link-search-no-results/index.js +54 -0
  16. package/dist/cjs/ui/link-picker/{link-search-no-results → link-search-list/link-search-no-results}/no-results-svg/index.js +0 -0
  17. package/dist/cjs/ui/link-picker/{link-search-no-results → link-search-list/link-search-no-results}/no-results-svg/styled.js +0 -0
  18. package/dist/cjs/ui/link-picker/link-search-list/link-search-no-results/styled.js +17 -0
  19. package/dist/cjs/ui/link-picker/link-search-list/styled.js +13 -6
  20. package/dist/cjs/ui/link-picker/messages.js +0 -50
  21. package/dist/cjs/ui/link-picker/styled.js +16 -11
  22. package/dist/cjs/ui/link-picker/text-input/styled.js +1 -1
  23. package/dist/cjs/version.json +1 -1
  24. package/dist/es2019/analytics.codegen.js +1 -1
  25. package/dist/es2019/{ui/link-picker → common/utils}/url.js +0 -0
  26. package/dist/es2019/controllers/use-fix-height/index.js +19 -0
  27. package/dist/es2019/services/use-plugins/index.js +35 -57
  28. package/dist/es2019/services/use-plugins/reducer.js +37 -0
  29. package/dist/es2019/services/use-plugins/utils.js +59 -0
  30. package/dist/es2019/services/use-search-query/index.js +1 -1
  31. package/dist/es2019/services/with-link-picker-analytics/index.js +15 -0
  32. package/dist/es2019/ui/link-picker/form-footer/index.js +51 -0
  33. package/dist/es2019/ui/link-picker/form-footer/styled.js +5 -0
  34. package/dist/es2019/ui/link-picker/index.js +28 -69
  35. package/dist/es2019/ui/link-picker/link-search-error/index.js +40 -4
  36. package/dist/es2019/ui/link-picker/link-search-list/index.js +60 -14
  37. package/dist/es2019/ui/link-picker/link-search-list/link-search-no-results/index.js +35 -0
  38. package/dist/es2019/ui/link-picker/{link-search-no-results → link-search-list/link-search-no-results}/no-results-svg/index.js +0 -0
  39. package/dist/es2019/ui/link-picker/{link-search-no-results → link-search-list/link-search-no-results}/no-results-svg/styled.js +0 -0
  40. package/dist/es2019/ui/link-picker/link-search-list/link-search-no-results/styled.js +6 -0
  41. package/dist/es2019/ui/link-picker/link-search-list/styled.js +23 -2
  42. package/dist/es2019/ui/link-picker/messages.js +0 -50
  43. package/dist/es2019/ui/link-picker/styled.js +20 -15
  44. package/dist/es2019/ui/link-picker/text-input/styled.js +3 -1
  45. package/dist/es2019/version.json +1 -1
  46. package/dist/esm/analytics.codegen.js +1 -1
  47. package/dist/esm/{ui/link-picker → common/utils}/url.js +0 -0
  48. package/dist/esm/controllers/use-fix-height/index.js +19 -0
  49. package/dist/esm/services/use-plugins/index.js +49 -94
  50. package/dist/esm/services/use-plugins/reducer.js +43 -0
  51. package/dist/esm/services/use-plugins/utils.js +111 -0
  52. package/dist/esm/services/use-search-query/index.js +1 -1
  53. package/dist/esm/services/with-link-picker-analytics/index.js +17 -0
  54. package/dist/esm/ui/link-picker/form-footer/index.js +53 -0
  55. package/dist/esm/ui/link-picker/form-footer/styled.js +6 -0
  56. package/dist/esm/ui/link-picker/index.js +29 -74
  57. package/dist/esm/ui/link-picker/link-search-error/index.js +41 -5
  58. package/dist/esm/ui/link-picker/link-search-list/index.js +67 -13
  59. package/dist/esm/ui/link-picker/link-search-list/link-search-no-results/index.js +37 -0
  60. package/dist/esm/ui/link-picker/{link-search-no-results → link-search-list/link-search-no-results}/no-results-svg/index.js +0 -0
  61. package/dist/esm/ui/link-picker/{link-search-no-results → link-search-list/link-search-no-results}/no-results-svg/styled.js +0 -0
  62. package/dist/esm/ui/link-picker/link-search-list/link-search-no-results/styled.js +6 -0
  63. package/dist/esm/ui/link-picker/link-search-list/styled.js +11 -5
  64. package/dist/esm/ui/link-picker/messages.js +0 -50
  65. package/dist/esm/ui/link-picker/styled.js +14 -11
  66. package/dist/esm/ui/link-picker/text-input/styled.js +1 -1
  67. package/dist/esm/version.json +1 -1
  68. package/dist/types/analytics.codegen.d.ts +7 -4
  69. package/dist/types/{ui/link-picker → common/utils}/url.d.ts +0 -0
  70. package/dist/types/controllers/use-fix-height/index.d.ts +8 -0
  71. package/dist/types/services/use-plugins/reducer.d.ts +30 -0
  72. package/dist/types/services/use-plugins/utils.d.ts +18 -0
  73. package/dist/types/services/with-link-picker-analytics/index.d.ts +4 -0
  74. package/dist/types/ui/link-picker/form-footer/index.d.ts +13 -0
  75. package/dist/types/ui/link-picker/form-footer/styled.d.ts +1 -0
  76. package/dist/types/ui/link-picker/index.d.ts +19 -19
  77. package/dist/types/ui/link-picker/link-search-error/index.d.ts +19 -3
  78. package/dist/types/ui/link-picker/link-search-list/index.d.ts +30 -5
  79. package/dist/types/ui/link-picker/link-search-list/link-search-no-results/index.d.ts +19 -0
  80. package/dist/types/ui/link-picker/{link-search-no-results → link-search-list/link-search-no-results}/no-results-svg/index.d.ts +0 -0
  81. package/dist/types/ui/link-picker/{link-search-no-results → link-search-list/link-search-no-results}/no-results-svg/styled.d.ts +0 -0
  82. package/dist/types/ui/link-picker/link-search-list/link-search-no-results/styled.d.ts +1 -0
  83. package/dist/types/ui/link-picker/link-search-list/styled.d.ts +1 -0
  84. package/dist/types/ui/link-picker/messages.d.ts +0 -50
  85. package/dist/types/ui/link-picker/styled.d.ts +5 -1
  86. package/package.json +12 -12
  87. package/report.api.md +2 -0
  88. package/dist/cjs/ui/link-picker/link-search-no-results/index.js +0 -27
  89. package/dist/es2019/ui/link-picker/link-search-no-results/index.js +0 -10
  90. package/dist/esm/ui/link-picker/link-search-no-results/index.js +0 -14
  91. package/dist/types/ui/link-picker/link-search-no-results/index.d.ts +0 -4
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/link-picker",
3
- "version": "1.8.2",
3
+ "version": "1.8.5",
4
4
  "sideEffects": false
5
5
  }
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Generates analytics utilities from the package analytics spec yaml
5
5
  *
6
- * @codegen <<SignedSource::ffa7ec78cc793f941d06cdb25b07dc8a>>
6
+ * @codegen <<SignedSource::115bafba068f36f76da67200ee2d08c4>>
7
7
  * @codegenCommand yarn workspace @atlaskit/link-picker run codegen-analytics
8
8
  */
9
9
  function createEventPayload(eventKey, attributes) {
@@ -0,0 +1,19 @@
1
+ import { useLayoutEffect, useRef } from 'react';
2
+
3
+ const useFixHeight = shouldFixHeight => {
4
+ const ref = useRef(null);
5
+ const currentHeight = useRef(null);
6
+ useLayoutEffect(() => {
7
+ if (ref.current) {
8
+ currentHeight.current = ref.current.getBoundingClientRect().height;
9
+ }
10
+ });
11
+ return {
12
+ ref,
13
+ style: shouldFixHeight ? {
14
+ minHeight: currentHeight.current || 'auto'
15
+ } : undefined
16
+ };
17
+ };
18
+
19
+ export default useFixHeight;
@@ -1,25 +1,10 @@
1
- import { useEffect, useReducer, useMemo, useRef, useState, useCallback } from 'react';
1
+ import { useEffect, useMemo, useState, useCallback } from 'react';
2
2
  import { RECENT_SEARCH_LIST_SIZE } from '../../ui/link-picker';
3
-
4
- function reducer(state, payload) {
5
- return { ...state,
6
- ...payload
7
- };
8
- }
9
-
3
+ import { CancellationError, resolvePluginUpdates } from './utils';
4
+ import { usePluginReducer } from './reducer';
10
5
  export function usePlugins(state, activeTab, plugins) {
11
6
  const [retries, setRetries] = useState(0);
12
- const [pluginState, dispatch] = useReducer(reducer, {
13
- items: null,
14
- error: null,
15
- isLoading: false
16
- });
17
- const {
18
- items,
19
- isLoading,
20
- error
21
- } = pluginState;
22
- const queryVersion = useRef(0);
7
+ const [pluginState, dispatch] = usePluginReducer();
23
8
  const activePlugin = plugins === null || plugins === void 0 ? void 0 : plugins[activeTab];
24
9
  useEffect(() => {
25
10
  if (!activePlugin) {
@@ -28,62 +13,50 @@ export function usePlugins(state, activeTab, plugins) {
28
13
 
29
14
  if (!state) {
30
15
  dispatch({
31
- items: null,
32
- isLoading: false,
33
- error: null
16
+ type: 'CLEAR'
34
17
  });
35
18
  return;
36
19
  }
37
20
 
38
- const updates = activePlugin.resolve(state);
39
21
  dispatch({
40
- items: null,
41
- isLoading: true,
42
- error: null
22
+ type: 'LOADING'
43
23
  });
44
- const newQuery = ++queryVersion.current;
24
+ const {
25
+ next,
26
+ cancel
27
+ } = resolvePluginUpdates(activePlugin, state);
45
28
 
46
29
  const updateResults = async () => {
47
30
  try {
48
- while (newQuery === queryVersion.current) {
49
- let done = false;
50
- let value;
51
-
52
- if (updates instanceof Promise) {
53
- done = true;
54
- value = await updates;
55
- } else {
56
- var _result$done;
57
-
58
- const result = await updates.next();
59
- done = (_result$done = result.done) !== null && _result$done !== void 0 ? _result$done : false;
60
- value = result.value;
61
- }
62
-
63
- if (newQuery !== queryVersion.current) {
64
- return;
65
- }
31
+ let isLoading = true;
66
32
 
33
+ while (isLoading) {
34
+ const {
35
+ value,
36
+ done
37
+ } = await next();
38
+ isLoading = !done;
67
39
  dispatch({
68
- items: limit(value.data),
69
- isLoading: !done
40
+ type: 'SUCCESS',
41
+ payload: {
42
+ items: limit(value.data),
43
+ isLoading: !done
44
+ }
70
45
  });
71
-
72
- if (done) {
73
- return;
74
- }
75
46
  }
76
47
  } catch (error) {
77
- dispatch({
78
- error,
79
- items: null,
80
- isLoading: false
81
- });
48
+ if (!(error instanceof CancellationError)) {
49
+ dispatch({
50
+ type: 'ERROR',
51
+ payload: error
52
+ });
53
+ }
82
54
  }
83
55
  };
84
56
 
85
57
  updateResults();
86
- }, [activePlugin, queryVersion, state, retries]);
58
+ return cancel;
59
+ }, [activePlugin, state, retries, dispatch]);
87
60
  const tabs = useMemo(() => {
88
61
  if (!plugins || plugins.length <= 1) {
89
62
  return [];
@@ -96,6 +69,11 @@ export function usePlugins(state, activeTab, plugins) {
96
69
  const handleRetry = useCallback(() => {
97
70
  setRetries(prev => ++prev);
98
71
  }, []);
72
+ const {
73
+ items,
74
+ isLoading,
75
+ error
76
+ } = pluginState;
99
77
  return {
100
78
  tabs,
101
79
  items,
@@ -0,0 +1,37 @@
1
+ import { useReducer } from 'react';
2
+ export const ACTION_CLEAR = 'CLEAR';
3
+ export const ACTION_LOADING = 'LOADING';
4
+ export const ACTION_SUCCESS = 'SUCCESS';
5
+ export const ACTION_ERRORED = 'ERROR';
6
+ export const INITIAL_STATE = {
7
+ items: null,
8
+ error: null,
9
+ isLoading: false
10
+ };
11
+ export function reducer(state, action) {
12
+ switch (action.type) {
13
+ case ACTION_CLEAR:
14
+ return { ...INITIAL_STATE
15
+ };
16
+
17
+ case ACTION_LOADING:
18
+ return { ...INITIAL_STATE,
19
+ isLoading: true
20
+ };
21
+
22
+ case ACTION_SUCCESS:
23
+ return { ...state,
24
+ ...action.payload,
25
+ error: null
26
+ };
27
+
28
+ case ACTION_ERRORED:
29
+ return { ...INITIAL_STATE,
30
+ error: action.payload
31
+ };
32
+
33
+ default:
34
+ return state;
35
+ }
36
+ }
37
+ export const usePluginReducer = () => useReducer(reducer, INITIAL_STATE);
@@ -0,0 +1,59 @@
1
+ export class CancellationError extends Error {}
2
+ export const cancellable = promise => {
3
+ let reject;
4
+ return {
5
+ promise: new Promise((resolve, _reject) => {
6
+ reject = _reject;
7
+ promise.then(resolve, reject);
8
+ }),
9
+ cancel: () => {
10
+ reject(new CancellationError('Promise cancelled'));
11
+ }
12
+ };
13
+ };
14
+ /**
15
+ * Wraps the resolve with a cancellation wrapper and makes promise + generator plugin resolves more compatible
16
+ * Calling cancel for generator plugin prevents it from yielding any further updates
17
+ */
18
+
19
+ export const resolvePluginUpdates = (plugin, state) => {
20
+ const updates = plugin.resolve(state); // Promise plugin
21
+
22
+ if (updates instanceof Promise) {
23
+ const {
24
+ promise,
25
+ cancel
26
+ } = cancellable(updates);
27
+ return {
28
+ cancel,
29
+ next: async () => ({
30
+ value: await promise,
31
+ done: true
32
+ })
33
+ };
34
+ } // Generator plugin
35
+
36
+
37
+ const cancellationCallbacks = [];
38
+ let cancelled = false;
39
+ return {
40
+ cancel: () => {
41
+ cancelled = true;
42
+ cancellationCallbacks.forEach(cb => cb());
43
+ },
44
+ next: () => {
45
+ const {
46
+ promise,
47
+ cancel
48
+ } = cancellable(updates.next());
49
+
50
+ if (cancelled) {
51
+ cancel();
52
+ } else {
53
+ cancellationCallbacks.push(cancel);
54
+ }
55
+
56
+ return promise;
57
+ }
58
+ };
59
+ };
@@ -1,5 +1,5 @@
1
1
  import { useRef } from 'react';
2
- import { isSafeUrl } from '../../ui/link-picker/url';
2
+ import { isSafeUrl } from '../../common/utils/url';
3
3
  export function useSearchQuery(state) {
4
4
  var _queryState$current;
5
5
 
@@ -0,0 +1,15 @@
1
+ import React, { useMemo } from 'react';
2
+ import { AnalyticsContext } from '@atlaskit/analytics-next';
3
+ import { normalizeUrl } from '../../common/utils/url';
4
+ export function withLinkPickerAnalyticsContext(WrappedComponent) {
5
+ return props => {
6
+ const data = useMemo(() => ({
7
+ attributes: {
8
+ linkState: normalizeUrl(props.url) ? 'editLink' : 'newLink'
9
+ }
10
+ }), [props.url]);
11
+ return /*#__PURE__*/React.createElement(AnalyticsContext, {
12
+ data: data
13
+ }, /*#__PURE__*/React.createElement(WrappedComponent, props));
14
+ };
15
+ }
@@ -0,0 +1,51 @@
1
+ import _extends from "@babel/runtime/helpers/extends";
2
+
3
+ /** @jsx jsx */
4
+ import { jsx } from '@emotion/react';
5
+ import { useIntl, defineMessages } from 'react-intl-next';
6
+ import Button, { ButtonGroup } from '@atlaskit/button';
7
+ import { formFooterStyles } from './styled';
8
+ import { memo } from 'react';
9
+ const messages = defineMessages({
10
+ cancelButton: {
11
+ id: 'fabric.linkPicker.button.cancel',
12
+ defaultMessage: 'Cancel',
13
+ description: 'Button to cancel and dismiss the link picker'
14
+ },
15
+ saveButton: {
16
+ id: 'fabric.linkPicker.button.save',
17
+ defaultMessage: 'Save',
18
+ description: 'Button to save edited link'
19
+ },
20
+ insertButton: {
21
+ id: 'fabric.linkPicker.button.insert',
22
+ defaultMessage: 'Insert',
23
+ description: 'Button to insert searched or selected link'
24
+ }
25
+ });
26
+ export const testIds = {
27
+ insertButton: 'link-picker-insert-button',
28
+ cancelButton: 'link-picker-cancel-button'
29
+ };
30
+
31
+ const FormFooter = ({
32
+ isEditing,
33
+ onCancel,
34
+ ...restProps
35
+ }) => {
36
+ const intl = useIntl();
37
+ const insertButtonMsg = isEditing ? messages.saveButton : messages.insertButton;
38
+ return jsx("footer", _extends({
39
+ css: formFooterStyles
40
+ }, restProps), jsx(ButtonGroup, null, jsx(Button, {
41
+ appearance: "default",
42
+ onClick: onCancel,
43
+ testId: testIds.cancelButton
44
+ }, intl.formatMessage(messages.cancelButton)), jsx(Button, {
45
+ type: "submit",
46
+ appearance: "primary",
47
+ testId: testIds.insertButton
48
+ }, intl.formatMessage(insertButtonMsg))));
49
+ };
50
+
51
+ export default /*#__PURE__*/memo(FormFooter);
@@ -0,0 +1,5 @@
1
+ import { css } from '@emotion/react';
2
+ export const formFooterStyles = css`
3
+ display: flex;
4
+ justify-content: flex-end;
5
+ `;
@@ -1,12 +1,10 @@
1
1
  import _extends from "@babel/runtime/helpers/extends";
2
2
 
3
3
  /** @jsx jsx */
4
- import { Fragment, useCallback, useEffect, useLayoutEffect, useReducer } from 'react';
4
+ import { Fragment, useCallback, useEffect, useLayoutEffect, useReducer, memo } from 'react';
5
5
  import { jsx } from '@emotion/react';
6
6
  import { useIntl, FormattedMessage } from 'react-intl-next';
7
7
  import { useAnalyticsEvents } from '@atlaskit/analytics-next';
8
- import Button, { ButtonGroup } from '@atlaskit/button';
9
- import { FormFooter } from '@atlaskit/form';
10
8
  import EditorSearchIcon from '@atlaskit/icon/glyph/editor/search';
11
9
  import Tabs, { Tab, TabList } from '@atlaskit/tabs';
12
10
  import VisuallyHidden from '@atlaskit/visually-hidden';
@@ -14,16 +12,18 @@ import createEventPayload from '../../analytics.codegen';
14
12
  import { ANALYTICS_CHANNEL } from '../../common/constants';
15
13
  import { usePlugins } from '../../services/use-plugins';
16
14
  import { useSearchQuery } from '../../services/use-search-query';
15
+ import { withLinkPickerAnalyticsContext } from '../../services/with-link-picker-analytics';
17
16
  import { messages } from './messages';
18
17
  import PanelTextInput from './text-input';
19
- import LinkSearchList from './link-search-list';
20
- import { normalizeUrl, isSafeUrl } from './url';
21
- import { rootContainerStyles, searchIconStyles, listTitleStyles, tabsWrapperStyles } from './styled';
18
+ import { normalizeUrl, isSafeUrl } from '../../common/utils/url';
19
+ import useFixHeight from '../../controllers/use-fix-height';
20
+ import { rootContainerStyles, searchIconStyles, tabsWrapperStyles, flexColumnStyles, formFooterMargin } from './styled';
22
21
  import { browser } from './browser';
23
22
  import Announcer from './announcer';
24
- import LinkSearchNoResults from './link-search-no-results';
25
23
  import { transformTimeStamp } from './transformTimeStamp';
26
- import LinkSearchError from './link-search-error';
24
+ import LinkSearchList, { testIds as listTestIds } from './link-search-list';
25
+ import LinkSearchError, { testIds as searchErrorTestIds } from './link-search-error';
26
+ import FormFooter, { testIds as formFooterTestIds } from './form-footer';
27
27
  export const RECENT_SEARCH_LIST_SIZE = 5;
28
28
  export const CONTACT_SUPPORT_LINK = 'https://support.atlassian.com/contact/';
29
29
  export const testIds = {
@@ -31,18 +31,13 @@ export const testIds = {
31
31
  urlInputField: 'link-url',
32
32
  textInputField: 'link-text',
33
33
  searchIcon: 'link-picker-search-icon',
34
- insertButton: 'link-picker-insert-button',
35
- cancelButton: 'link-picker-cancel-button',
34
+ ...formFooterTestIds,
35
+ ...searchErrorTestIds,
36
+ ...listTestIds,
36
37
  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
38
  urlError: 'link-error',
43
39
  tabList: 'link-picker-tabs',
44
- tabItem: 'link-picker-tab',
45
- searchError: 'link-search-error'
40
+ tabItem: 'link-picker-tab'
46
41
  };
47
42
  const initState = {
48
43
  url: '',
@@ -75,7 +70,7 @@ function LinkPicker({
75
70
  url: initUrl,
76
71
  displayText: initDisplayText
77
72
  }) {
78
- var _queryState$query, _items$length, _errorFallback;
73
+ var _errorFallback;
79
74
 
80
75
  const {
81
76
  createAnalyticsEvent
@@ -103,6 +98,7 @@ function LinkPicker({
103
98
  retry,
104
99
  errorFallback
105
100
  } = usePlugins(queryState, activeTab, plugins);
101
+ const fixListHeightProps = useFixHeight(isLoading);
106
102
  const isEditing = !!initUrl;
107
103
  const selectedItem = items === null || items === void 0 ? void 0 : items[selectedIndex];
108
104
  const isSelectedItem = (selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.url) === url;
@@ -232,9 +228,6 @@ function LinkPicker({
232
228
  });
233
229
  }, [handleInsert, isSelectedItem, selectedItem, url]);
234
230
  const linkPlaceHolder = isActivePlugin ? messages.placeholder : messages.linkPlaceholder;
235
- const linkListTitle = (queryState === null || queryState === void 0 ? void 0 : (_queryState$query = queryState.query) === null || _queryState$query === void 0 ? void 0 : _queryState$query.length) !== 0 ? messages.titleResults : messages.titleRecentlyViewed;
236
- const insertButtonMsg = isEditing ? messages.saveButton : messages.insertButton;
237
- const noResults = (items === null || items === void 0 ? void 0 : items.length) === 0 && !error;
238
231
  const screenReaderDescriptionId = 'search-recent-links-field-description';
239
232
  const linkSearchListId = 'link-picker-search-list';
240
233
  const ariaActiveDescendant = selectedIndex > -1 ? `link-search-list-item-${selectedIndex}` : ''; // Added workaround with a screen reader Announcer specifically for VoiceOver + Safari
@@ -292,7 +285,7 @@ function LinkPicker({
292
285
  onClear: handleClear,
293
286
  onKeyDown: handleKeyDown,
294
287
  onChange: handleChangeText
295
- }), queryState && jsx(Fragment, null, tabs.length > 0 && jsx("div", {
288
+ }), isActivePlugin && !!queryState && jsx(Fragment, null, tabs.length > 0 && jsx("div", {
296
289
  css: tabsWrapperStyles
297
290
  }, jsx(Tabs, {
298
291
  id: testIds.tabList,
@@ -306,62 +299,28 @@ function LinkPicker({
306
299
  }, jsx(TabList, null, tabs.map(tab => jsx(Tab, {
307
300
  key: tab.tabTitle,
308
301
  testId: testIds.tabItem
309
- }, tab.tabTitle))))), !!(items !== null && items !== void 0 && items.length) && jsx("div", {
310
- css: listTitleStyles,
311
- id: testIds.resultListTitle,
312
- "data-testid": testIds.resultListTitle
313
- }, jsx(FormattedMessage, linkListTitle)), jsx(VisuallyHidden, {
314
- id: "fabric.smartcard.linkpicker.suggested.results"
315
- }, url && jsx(FormattedMessage, _extends({}, messages.searchLinkResults, {
316
- values: {
317
- count: (_items$length = items === null || items === void 0 ? void 0 : items.length) !== null && _items$length !== void 0 ? _items$length : 0
318
- },
319
- "aria-live": "polite",
320
- "aria-atomic": "true"
321
- }))), jsx(LinkSearchList, {
322
- ariaLabelledBy: testIds.resultListTitle,
323
- ariaControls: "fabric.smartcard.linkpicker.suggested.results",
302
+ }, tab.tabTitle))))), jsx("div", _extends({
303
+ css: flexColumnStyles
304
+ }, fixListHeightProps), !error && jsx(LinkSearchList, {
324
305
  id: linkSearchListId,
325
306
  role: "listbox",
326
- items: items !== null && items !== void 0 ? items : [],
307
+ items: items,
327
308
  isLoading: isLoading,
328
309
  selectedIndex: selectedIndex,
329
310
  activeIndex: activeIndex,
330
311
  onSelect: handleSelected,
331
312
  onMouseEnter: handleMouseEnterResultItem,
332
- onMouseLeave: handleMouseLeaveResultItem
333
- }), error && ((_errorFallback = errorFallback === null || errorFallback === void 0 ? void 0 : errorFallback(error, retry)) !== null && _errorFallback !== void 0 ? _errorFallback : jsx(LinkSearchError, {
334
- testId: testIds.searchError,
335
- header: intl.formatMessage(messages.searchErrorHeader),
336
- description: jsx(FormattedMessage, _extends({}, messages.searchErrorDescription, {
337
- values: {
338
- a: label => jsx(Button, {
339
- appearance: "link",
340
- spacing: "none",
341
- href: CONTACT_SUPPORT_LINK,
342
- target: "_blank",
343
- rel: "noopener noreferrer"
344
- }, label)
345
- }
346
- }))
347
- })), noResults && jsx(LinkSearchNoResults, {
348
- testId: testIds.emptyResultPage,
349
- header: intl.formatMessage(messages.noResults),
350
- description: intl.formatMessage(messages.noResultsDescription)
351
- })), jsx(FormFooter, {
352
- align: "end"
353
- }, jsx(ButtonGroup, null, jsx(Button, {
354
- appearance: "default",
355
- onClick: onCancel,
356
- testId: testIds.cancelButton
357
- }, intl.formatMessage(messages.cancelButton)), jsx(Button, {
358
- type: "submit",
359
- appearance: "primary",
360
- testId: testIds.insertButton
361
- }, intl.formatMessage(insertButtonMsg)))));
313
+ onMouseLeave: handleMouseLeaveResultItem,
314
+ error: error,
315
+ hasSearchTerm: !!(queryState !== null && queryState !== void 0 && queryState.query.length)
316
+ }), error && ((_errorFallback = errorFallback === null || errorFallback === void 0 ? void 0 : errorFallback(error, retry)) !== null && _errorFallback !== void 0 ? _errorFallback : jsx(LinkSearchError, null)))), jsx(FormFooter, {
317
+ css: !queryState || !(plugins !== null && plugins !== void 0 && plugins.length) ? formFooterMargin : undefined,
318
+ isEditing: isEditing,
319
+ onCancel: onCancel
320
+ }));
362
321
  }
363
322
 
364
- export default LinkPicker;
323
+ export default withLinkPickerAnalyticsContext( /*#__PURE__*/memo(LinkPicker));
365
324
 
366
325
  function getScreenReaderText(items, selectedIndex, intl) {
367
326
  if (items.length && selectedIndex > -1) {
@@ -1,10 +1,46 @@
1
1
  import _extends from "@babel/runtime/helpers/extends";
2
- import React from 'react';
2
+
3
+ /** @jsx jsx */
4
+ import { jsx } from '@emotion/react';
5
+ import { useIntl, FormattedMessage, defineMessages } from 'react-intl-next';
6
+ import Button from '@atlaskit/button';
7
+ export const CONTACT_SUPPORT_LINK = 'https://support.atlassian.com/contact/';
8
+ export const messages = defineMessages({
9
+ searchErrorHeader: {
10
+ id: 'fabric.linkPicker.search.error.heading',
11
+ defaultMessage: 'We’re having trouble loading data.',
12
+ description: 'Heading message shown when a search throws an error'
13
+ },
14
+ searchErrorDescription: {
15
+ id: 'fabric.linkPicker.search.error.description',
16
+ defaultMessage: 'Refresh the page, or contact <a>Atlassian Support</a> if this keeps happening.',
17
+ description: 'Describes possible actions when search throws an error'
18
+ }
19
+ });
3
20
  import EmptyState from '@atlaskit/empty-state';
4
21
  import GenericErrorSVG from '../../../common/generic-error-svg';
22
+ export const testIds = {
23
+ searchError: 'link-search-error'
24
+ };
5
25
 
6
- const LinkSearchError = props => /*#__PURE__*/React.createElement(EmptyState, _extends({}, props, {
7
- renderImage: () => /*#__PURE__*/React.createElement(GenericErrorSVG, null)
8
- }));
26
+ const LinkSearchError = () => {
27
+ const intl = useIntl();
28
+ return jsx(EmptyState, {
29
+ testId: testIds.searchError,
30
+ header: intl.formatMessage(messages.searchErrorHeader),
31
+ description: jsx(FormattedMessage, _extends({}, messages.searchErrorDescription, {
32
+ values: {
33
+ a: label => jsx(Button, {
34
+ appearance: "link",
35
+ spacing: "none",
36
+ href: CONTACT_SUPPORT_LINK,
37
+ target: "_blank",
38
+ rel: "noopener noreferrer"
39
+ }, label)
40
+ }
41
+ })),
42
+ renderImage: () => jsx(GenericErrorSVG, null)
43
+ });
44
+ };
9
45
 
10
46
  export default LinkSearchError;