@atlaskit/link-picker 1.8.4 → 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 (64) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/cjs/controllers/use-fix-height/index.js +27 -0
  3. package/dist/cjs/ui/link-picker/form-footer/index.js +76 -0
  4. package/dist/cjs/ui/link-picker/form-footer/styled.js +17 -0
  5. package/dist/cjs/ui/link-picker/index.js +29 -74
  6. package/dist/cjs/ui/link-picker/link-search-error/index.js +47 -6
  7. package/dist/cjs/ui/link-picker/link-search-list/index.js +89 -20
  8. package/dist/cjs/ui/link-picker/link-search-list/link-search-no-results/index.js +54 -0
  9. package/dist/cjs/ui/link-picker/{link-search-no-results → link-search-list/link-search-no-results}/no-results-svg/index.js +0 -0
  10. package/dist/cjs/ui/link-picker/{link-search-no-results → link-search-list/link-search-no-results}/no-results-svg/styled.js +0 -0
  11. package/dist/cjs/ui/link-picker/link-search-list/link-search-no-results/styled.js +17 -0
  12. package/dist/cjs/ui/link-picker/link-search-list/styled.js +13 -6
  13. package/dist/cjs/ui/link-picker/messages.js +0 -50
  14. package/dist/cjs/ui/link-picker/styled.js +16 -11
  15. package/dist/cjs/ui/link-picker/text-input/styled.js +1 -1
  16. package/dist/cjs/version.json +1 -1
  17. package/dist/es2019/controllers/use-fix-height/index.js +19 -0
  18. package/dist/es2019/ui/link-picker/form-footer/index.js +51 -0
  19. package/dist/es2019/ui/link-picker/form-footer/styled.js +5 -0
  20. package/dist/es2019/ui/link-picker/index.js +24 -66
  21. package/dist/es2019/ui/link-picker/link-search-error/index.js +40 -4
  22. package/dist/es2019/ui/link-picker/link-search-list/index.js +60 -14
  23. package/dist/es2019/ui/link-picker/link-search-list/link-search-no-results/index.js +35 -0
  24. package/dist/es2019/ui/link-picker/{link-search-no-results → link-search-list/link-search-no-results}/no-results-svg/index.js +0 -0
  25. package/dist/es2019/ui/link-picker/{link-search-no-results → link-search-list/link-search-no-results}/no-results-svg/styled.js +0 -0
  26. package/dist/es2019/ui/link-picker/link-search-list/link-search-no-results/styled.js +6 -0
  27. package/dist/es2019/ui/link-picker/link-search-list/styled.js +23 -2
  28. package/dist/es2019/ui/link-picker/messages.js +0 -50
  29. package/dist/es2019/ui/link-picker/styled.js +20 -15
  30. package/dist/es2019/ui/link-picker/text-input/styled.js +3 -1
  31. package/dist/es2019/version.json +1 -1
  32. package/dist/esm/controllers/use-fix-height/index.js +19 -0
  33. package/dist/esm/ui/link-picker/form-footer/index.js +53 -0
  34. package/dist/esm/ui/link-picker/form-footer/styled.js +6 -0
  35. package/dist/esm/ui/link-picker/index.js +25 -71
  36. package/dist/esm/ui/link-picker/link-search-error/index.js +41 -5
  37. package/dist/esm/ui/link-picker/link-search-list/index.js +67 -13
  38. package/dist/esm/ui/link-picker/link-search-list/link-search-no-results/index.js +37 -0
  39. package/dist/esm/ui/link-picker/{link-search-no-results → link-search-list/link-search-no-results}/no-results-svg/index.js +0 -0
  40. package/dist/esm/ui/link-picker/{link-search-no-results → link-search-list/link-search-no-results}/no-results-svg/styled.js +0 -0
  41. package/dist/esm/ui/link-picker/link-search-list/link-search-no-results/styled.js +6 -0
  42. package/dist/esm/ui/link-picker/link-search-list/styled.js +11 -5
  43. package/dist/esm/ui/link-picker/messages.js +0 -50
  44. package/dist/esm/ui/link-picker/styled.js +14 -11
  45. package/dist/esm/ui/link-picker/text-input/styled.js +1 -1
  46. package/dist/esm/version.json +1 -1
  47. package/dist/types/controllers/use-fix-height/index.d.ts +8 -0
  48. package/dist/types/ui/link-picker/form-footer/index.d.ts +13 -0
  49. package/dist/types/ui/link-picker/form-footer/styled.d.ts +1 -0
  50. package/dist/types/ui/link-picker/index.d.ts +16 -16
  51. package/dist/types/ui/link-picker/link-search-error/index.d.ts +19 -3
  52. package/dist/types/ui/link-picker/link-search-list/index.d.ts +30 -5
  53. package/dist/types/ui/link-picker/link-search-list/link-search-no-results/index.d.ts +19 -0
  54. 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
  55. 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
  56. package/dist/types/ui/link-picker/link-search-list/link-search-no-results/styled.d.ts +1 -0
  57. package/dist/types/ui/link-picker/link-search-list/styled.d.ts +1 -0
  58. package/dist/types/ui/link-picker/messages.d.ts +0 -50
  59. package/dist/types/ui/link-picker/styled.d.ts +5 -1
  60. package/package.json +6 -6
  61. package/dist/cjs/ui/link-picker/link-search-no-results/index.js +0 -27
  62. package/dist/es2019/ui/link-picker/link-search-no-results/index.js +0 -10
  63. package/dist/esm/ui/link-picker/link-search-no-results/index.js +0 -14
  64. package/dist/types/ui/link-picker/link-search-no-results/index.d.ts +0 -4
@@ -53,11 +53,6 @@ var messages = (0, _reactIntlNext.defineMessages)({
53
53
  defaultMessage: 'Suggestions will appear below as you type into the field',
54
54
  description: 'Describes what the search field does for screen reader users.'
55
55
  },
56
- searchLinkResults: {
57
- id: 'fabric.linkPicker.hyperlink.searchLinkResults',
58
- defaultMessage: '{count, plural, =0 {no results} one {# result} other {# results}} found',
59
- description: 'Announce search results for screen-reader users.'
60
- },
61
56
  linkAriaLabel: {
62
57
  id: 'fabric.linkPicker.hyperlink.linkAriaLabel',
63
58
  defaultMessage: 'Link label',
@@ -77,51 +72,6 @@ var messages = (0, _reactIntlNext.defineMessages)({
77
72
  id: 'fabric.linkPicker.time.ago',
78
73
  defaultMessage: 'ago',
79
74
  description: 'Some time ago'
80
- },
81
- titleRecentlyViewed: {
82
- id: 'fabric.linkPicker.listTitle.recentlyViewed',
83
- defaultMessage: 'Recently Viewed',
84
- description: 'Describes type of items shown in the list for screen-reader users'
85
- },
86
- titleResults: {
87
- id: 'fabric.linkPicker.listTitle.results',
88
- defaultMessage: 'Results',
89
- description: 'Describes type of items shown in the list for screen-reader users'
90
- },
91
- cancelButton: {
92
- id: 'fabric.linkPicker.button.cancel',
93
- defaultMessage: 'Cancel',
94
- description: 'Button to cancel and dismiss the link picker'
95
- },
96
- insertButton: {
97
- id: 'fabric.linkPicker.button.insert',
98
- defaultMessage: 'Insert',
99
- description: 'Button to insert searched or selected link'
100
- },
101
- noResults: {
102
- id: 'fabric.linkPicker.search.noResults.heading',
103
- defaultMessage: 'We couldn’t find anything matching your search.',
104
- description: 'Heading message shown when a search has no results'
105
- },
106
- noResultsDescription: {
107
- id: 'fabric.linkPicker.search.noResults.description',
108
- defaultMessage: 'Try again with a different term.',
109
- description: 'Describes possible action when a search returns no results'
110
- },
111
- saveButton: {
112
- id: 'fabric.linkPicker.button.save',
113
- defaultMessage: 'Save',
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'
125
75
  }
126
76
  });
127
77
  exports.messages = messages;
@@ -5,7 +5,7 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
5
5
  Object.defineProperty(exports, "__esModule", {
6
6
  value: true
7
7
  });
8
- exports.tabsWrapperStyles = exports.searchIconStyles = exports.rootContainerStylesForLoader = exports.rootContainerStyles = exports.listTitleStyles = void 0;
8
+ exports.tabsWrapperStyles = exports.searchIconStyles = exports.rootContainerStylesForLoader = exports.rootContainerStyles = exports.formFooterMargin = exports.flexColumnStyles = void 0;
9
9
 
10
10
  var _taggedTemplateLiteral2 = _interopRequireDefault(require("@babel/runtime/helpers/taggedTemplateLiteral"));
11
11
 
@@ -15,21 +15,26 @@ var _react = require("@emotion/react");
15
15
 
16
16
  var _colors = require("@atlaskit/theme/colors");
17
17
 
18
- var _theme = require("@atlaskit/theme");
19
-
20
18
  var _constants = require("@atlaskit/theme/constants");
21
19
 
22
- var _templateObject, _templateObject2, _templateObject3, _templateObject4, _templateObject5;
20
+ var _templateObject, _templateObject2, _templateObject3, _templateObject4, _templateObject5, _templateObject6;
23
21
 
24
22
  var LINK_PICKER_WIDTH_IN_PX = 342;
25
- var LINK_PICKER_MIN_HEIGHT_IN_PX = 234;
26
- var rootContainerStyles = (0, _react.css)(_templateObject || (_templateObject = (0, _taggedTemplateLiteral2.default)(["\n width: ", "px;\n padding: ", "px;\n box-sizing: border-box;\n line-height: initial;\n min-height: ", "px;\n"])), LINK_PICKER_WIDTH_IN_PX, (0, _constants.gridSize)() * 2, LINK_PICKER_MIN_HEIGHT_IN_PX);
23
+ var LINK_PICKER_MIN_HEIGHT_IN_PX = 220;
24
+ var gridSize = (0, _constants.gridSize)();
25
+ /**
26
+ * Half padding on the top as the form field has a `gridSize()` margin top that cannot be overridden
27
+ */
28
+
29
+ var rootContainerStyles = (0, _react.css)(_templateObject || (_templateObject = (0, _taggedTemplateLiteral2.default)(["\n width: ", "px;\n padding: ", "px ", "px ", "px;\n box-sizing: border-box;\n line-height: initial;\n min-height: ", "px;\n"])), LINK_PICKER_WIDTH_IN_PX, gridSize, gridSize * 2, gridSize * 2, LINK_PICKER_MIN_HEIGHT_IN_PX);
27
30
  exports.rootContainerStyles = rootContainerStyles;
28
31
  var rootContainerStylesForLoader = (0, _react.css)(_templateObject2 || (_templateObject2 = (0, _taggedTemplateLiteral2.default)(["\n ", "\n display: flex;\n align-items: center;\n justify-content: center;\n"])), rootContainerStyles);
29
32
  exports.rootContainerStylesForLoader = rootContainerStylesForLoader;
30
- var searchIconStyles = (0, _react.css)(_templateObject3 || (_templateObject3 = (0, _taggedTemplateLiteral2.default)(["\n margin-left: ", "px;\n color: ", ";\n cursor: default;\n"])), (0, _constants.gridSize)() / 2, (0, _tokens.token)('color.icon', _colors.N500));
33
+ var searchIconStyles = (0, _react.css)(_templateObject3 || (_templateObject3 = (0, _taggedTemplateLiteral2.default)(["\n margin-left: ", "px;\n color: ", ";\n cursor: default;\n"])), gridSize / 2, (0, _tokens.token)('color.icon', _colors.N500));
31
34
  exports.searchIconStyles = searchIconStyles;
32
- var listTitleStyles = (0, _react.css)(_templateObject4 || (_templateObject4 = (0, _taggedTemplateLiteral2.default)(["\n ", "\n text-transform: uppercase;\n margin-bottom: ", "px;\n"])), _theme.typography.h100(), (0, _constants.gridSize)() / 2);
33
- exports.listTitleStyles = listTitleStyles;
34
- var tabsWrapperStyles = (0, _react.css)(_templateObject5 || (_templateObject5 = (0, _taggedTemplateLiteral2.default)(["\n margin-left: -", "px;\n margin-right: -", "px;\n"])), (0, _constants.gridSize)(), (0, _constants.gridSize)());
35
- exports.tabsWrapperStyles = tabsWrapperStyles;
35
+ var tabsWrapperStyles = (0, _react.css)(_templateObject4 || (_templateObject4 = (0, _taggedTemplateLiteral2.default)(["\n margin-top: ", "px;\n margin-left: -", "px;\n margin-right: -", "px;\n"])), gridSize * 1.5, gridSize, gridSize);
36
+ exports.tabsWrapperStyles = tabsWrapperStyles;
37
+ var flexColumnStyles = (0, _react.css)(_templateObject5 || (_templateObject5 = (0, _taggedTemplateLiteral2.default)(["\n display: flex;\n flex-direction: column;\n"])));
38
+ exports.flexColumnStyles = flexColumnStyles;
39
+ var formFooterMargin = (0, _react.css)(_templateObject6 || (_templateObject6 = (0, _taggedTemplateLiteral2.default)(["\n margin-top: ", "px;\n"])), gridSize * 2);
40
+ exports.formFooterMargin = formFooterMargin;
@@ -21,5 +21,5 @@ var _templateObject, _templateObject2;
21
21
 
22
22
  var clearTextButtonStyles = (0, _react.css)(_templateObject || (_templateObject = (0, _taggedTemplateLiteral2.default)(["\n padding: 0;\n margin-right: ", "px;\n color: ", ";\n background: transparent;\n border: none;\n cursor: pointer;\n"])), (0, _constants.gridSize)() / 2, (0, _tokens.token)('color.icon.subtle', _colors.N500));
23
23
  exports.clearTextButtonStyles = clearTextButtonStyles;
24
- var fieldStyles = (0, _react.css)(_templateObject2 || (_templateObject2 = (0, _taggedTemplateLiteral2.default)(["\n margin-bottom: ", "px;\n"])), (0, _constants.gridSize)() * 2);
24
+ var fieldStyles = (0, _react.css)(_templateObject2 || (_templateObject2 = (0, _taggedTemplateLiteral2.default)(["\n & + & {\n margin-top: ", "px;\n }\n"])), (0, _constants.gridSize)() * 2);
25
25
  exports.fieldStyles = fieldStyles;
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/link-picker",
3
- "version": "1.8.4",
3
+ "version": "1.8.5",
4
4
  "sideEffects": false
5
5
  }
@@ -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;
@@ -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
+ `;
@@ -5,8 +5,6 @@ import { Fragment, useCallback, useEffect, useLayoutEffect, useReducer, memo } f
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';
@@ -17,14 +15,15 @@ import { useSearchQuery } from '../../services/use-search-query';
17
15
  import { withLinkPickerAnalyticsContext } from '../../services/with-link-picker-analytics';
18
16
  import { messages } from './messages';
19
17
  import PanelTextInput from './text-input';
20
- import LinkSearchList from './link-search-list';
21
18
  import { normalizeUrl, isSafeUrl } from '../../common/utils/url';
22
- import { rootContainerStyles, searchIconStyles, listTitleStyles, tabsWrapperStyles } from './styled';
19
+ import useFixHeight from '../../controllers/use-fix-height';
20
+ import { rootContainerStyles, searchIconStyles, tabsWrapperStyles, flexColumnStyles, formFooterMargin } from './styled';
23
21
  import { browser } from './browser';
24
22
  import Announcer from './announcer';
25
- import LinkSearchNoResults from './link-search-no-results';
26
23
  import { transformTimeStamp } from './transformTimeStamp';
27
- 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';
28
27
  export const RECENT_SEARCH_LIST_SIZE = 5;
29
28
  export const CONTACT_SUPPORT_LINK = 'https://support.atlassian.com/contact/';
30
29
  export const testIds = {
@@ -32,18 +31,13 @@ export const testIds = {
32
31
  urlInputField: 'link-url',
33
32
  textInputField: 'link-text',
34
33
  searchIcon: 'link-picker-search-icon',
35
- insertButton: 'link-picker-insert-button',
36
- cancelButton: 'link-picker-cancel-button',
34
+ ...formFooterTestIds,
35
+ ...searchErrorTestIds,
36
+ ...listTestIds,
37
37
  clearUrlButton: 'clear-text',
38
- resultListTitle: 'link-picker-list-title',
39
- emptyResultPage: 'link-search-no-results',
40
- searchResultList: 'link-search-list',
41
- searchResultItem: 'link-search-list-item',
42
- searchResultLoadingIndicator: 'link-picker.results-loading-indicator',
43
38
  urlError: 'link-error',
44
39
  tabList: 'link-picker-tabs',
45
- tabItem: 'link-picker-tab',
46
- searchError: 'link-search-error'
40
+ tabItem: 'link-picker-tab'
47
41
  };
48
42
  const initState = {
49
43
  url: '',
@@ -76,7 +70,7 @@ function LinkPicker({
76
70
  url: initUrl,
77
71
  displayText: initDisplayText
78
72
  }) {
79
- var _queryState$query, _items$length, _errorFallback;
73
+ var _errorFallback;
80
74
 
81
75
  const {
82
76
  createAnalyticsEvent
@@ -104,6 +98,7 @@ function LinkPicker({
104
98
  retry,
105
99
  errorFallback
106
100
  } = usePlugins(queryState, activeTab, plugins);
101
+ const fixListHeightProps = useFixHeight(isLoading);
107
102
  const isEditing = !!initUrl;
108
103
  const selectedItem = items === null || items === void 0 ? void 0 : items[selectedIndex];
109
104
  const isSelectedItem = (selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.url) === url;
@@ -233,9 +228,6 @@ function LinkPicker({
233
228
  });
234
229
  }, [handleInsert, isSelectedItem, selectedItem, url]);
235
230
  const linkPlaceHolder = isActivePlugin ? messages.placeholder : messages.linkPlaceholder;
236
- 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;
237
- const insertButtonMsg = isEditing ? messages.saveButton : messages.insertButton;
238
- const noResults = (items === null || items === void 0 ? void 0 : items.length) === 0 && !error;
239
231
  const screenReaderDescriptionId = 'search-recent-links-field-description';
240
232
  const linkSearchListId = 'link-picker-search-list';
241
233
  const ariaActiveDescendant = selectedIndex > -1 ? `link-search-list-item-${selectedIndex}` : ''; // Added workaround with a screen reader Announcer specifically for VoiceOver + Safari
@@ -293,7 +285,7 @@ function LinkPicker({
293
285
  onClear: handleClear,
294
286
  onKeyDown: handleKeyDown,
295
287
  onChange: handleChangeText
296
- }), queryState && jsx(Fragment, null, tabs.length > 0 && jsx("div", {
288
+ }), isActivePlugin && !!queryState && jsx(Fragment, null, tabs.length > 0 && jsx("div", {
297
289
  css: tabsWrapperStyles
298
290
  }, jsx(Tabs, {
299
291
  id: testIds.tabList,
@@ -307,59 +299,25 @@ function LinkPicker({
307
299
  }, jsx(TabList, null, tabs.map(tab => jsx(Tab, {
308
300
  key: tab.tabTitle,
309
301
  testId: testIds.tabItem
310
- }, tab.tabTitle))))), !!(items !== null && items !== void 0 && items.length) && jsx("div", {
311
- css: listTitleStyles,
312
- id: testIds.resultListTitle,
313
- "data-testid": testIds.resultListTitle
314
- }, jsx(FormattedMessage, linkListTitle)), jsx(VisuallyHidden, {
315
- id: "fabric.smartcard.linkpicker.suggested.results"
316
- }, url && jsx(FormattedMessage, _extends({}, messages.searchLinkResults, {
317
- values: {
318
- count: (_items$length = items === null || items === void 0 ? void 0 : items.length) !== null && _items$length !== void 0 ? _items$length : 0
319
- },
320
- "aria-live": "polite",
321
- "aria-atomic": "true"
322
- }))), jsx(LinkSearchList, {
323
- ariaLabelledBy: testIds.resultListTitle,
324
- ariaControls: "fabric.smartcard.linkpicker.suggested.results",
302
+ }, tab.tabTitle))))), jsx("div", _extends({
303
+ css: flexColumnStyles
304
+ }, fixListHeightProps), !error && jsx(LinkSearchList, {
325
305
  id: linkSearchListId,
326
306
  role: "listbox",
327
- items: items !== null && items !== void 0 ? items : [],
307
+ items: items,
328
308
  isLoading: isLoading,
329
309
  selectedIndex: selectedIndex,
330
310
  activeIndex: activeIndex,
331
311
  onSelect: handleSelected,
332
312
  onMouseEnter: handleMouseEnterResultItem,
333
- onMouseLeave: handleMouseLeaveResultItem
334
- }), error && ((_errorFallback = errorFallback === null || errorFallback === void 0 ? void 0 : errorFallback(error, retry)) !== null && _errorFallback !== void 0 ? _errorFallback : jsx(LinkSearchError, {
335
- testId: testIds.searchError,
336
- header: intl.formatMessage(messages.searchErrorHeader),
337
- description: jsx(FormattedMessage, _extends({}, messages.searchErrorDescription, {
338
- values: {
339
- a: label => jsx(Button, {
340
- appearance: "link",
341
- spacing: "none",
342
- href: CONTACT_SUPPORT_LINK,
343
- target: "_blank",
344
- rel: "noopener noreferrer"
345
- }, label)
346
- }
347
- }))
348
- })), noResults && jsx(LinkSearchNoResults, {
349
- testId: testIds.emptyResultPage,
350
- header: intl.formatMessage(messages.noResults),
351
- description: intl.formatMessage(messages.noResultsDescription)
352
- })), jsx(FormFooter, {
353
- align: "end"
354
- }, jsx(ButtonGroup, null, jsx(Button, {
355
- appearance: "default",
356
- onClick: onCancel,
357
- testId: testIds.cancelButton
358
- }, intl.formatMessage(messages.cancelButton)), jsx(Button, {
359
- type: "submit",
360
- appearance: "primary",
361
- testId: testIds.insertButton
362
- }, 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
+ }));
363
321
  }
364
322
 
365
323
  export default withLinkPickerAnalyticsContext( /*#__PURE__*/memo(LinkPicker));
@@ -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;
@@ -1,11 +1,38 @@
1
+ import _extends from "@babel/runtime/helpers/extends";
2
+
1
3
  /** @jsx jsx */
4
+ import { forwardRef, Fragment } from 'react';
2
5
  import { jsx } from '@emotion/react';
6
+ import { defineMessages, FormattedMessage } from 'react-intl-next';
3
7
  import Spinner from '@atlaskit/spinner';
8
+ import VisuallyHidden from '@atlaskit/visually-hidden';
4
9
  import LinkSearchListItem from '../list-item';
5
- import { listContainerStyles, spinnerContainerStyles, listStyles } from './styled';
6
- import { testIds } from '../';
7
-
8
- const LinkSearchList = ({
10
+ import { listContainerStyles, spinnerContainerStyles, listStyles, listTitleStyles } from './styled';
11
+ import LinkSearchNoResults, { testIds as noResultsTestIds } from './link-search-no-results';
12
+ export const messages = defineMessages({
13
+ titleRecentlyViewed: {
14
+ id: 'fabric.linkPicker.listTitle.recentlyViewed',
15
+ defaultMessage: 'Recently Viewed',
16
+ description: 'Describes type of items shown in the list for screen-reader users'
17
+ },
18
+ titleResults: {
19
+ id: 'fabric.linkPicker.listTitle.results',
20
+ defaultMessage: 'Results',
21
+ description: 'Describes type of items shown in the list for screen-reader users'
22
+ },
23
+ searchLinkResults: {
24
+ id: 'fabric.linkPicker.hyperlink.searchLinkResults',
25
+ defaultMessage: '{count, plural, =0 {no results} one {# result} other {# results}} found',
26
+ description: 'Announce search results for screen-reader users.'
27
+ }
28
+ });
29
+ export const testIds = { ...noResultsTestIds,
30
+ resultListTitle: 'link-picker-list-title',
31
+ searchResultItem: 'link-search-list-item',
32
+ searchResultList: 'link-search-list',
33
+ searchResultLoadingIndicator: 'link-picker.results-loading-indicator'
34
+ };
35
+ const LinkSearchList = /*#__PURE__*/forwardRef(({
9
36
  onSelect,
10
37
  onMouseEnter,
11
38
  onMouseLeave,
@@ -16,18 +43,37 @@ const LinkSearchList = ({
16
43
  ariaControls,
17
44
  ariaLabelledBy,
18
45
  role,
19
- id
20
- }) => {
46
+ id,
47
+ hasSearchTerm,
48
+ ...restProps
49
+ }, ref) => {
21
50
  let itemsContent;
22
51
  let loadingContent;
52
+ const linkListTitle = hasSearchTerm ? messages.titleResults : messages.titleRecentlyViewed;
53
+
54
+ if ((items === null || items === void 0 ? void 0 : items.length) === 0) {
55
+ return jsx(LinkSearchNoResults, null);
56
+ }
23
57
 
24
58
  if (items && items.length > 0) {
25
- itemsContent = jsx("ul", {
59
+ itemsContent = jsx(Fragment, null, jsx("div", {
60
+ css: listTitleStyles,
61
+ id: testIds.resultListTitle,
62
+ "data-testid": testIds.resultListTitle
63
+ }, jsx(FormattedMessage, linkListTitle)), jsx(VisuallyHidden, {
64
+ id: "fabric.smartcard.linkpicker.suggested.results"
65
+ }, hasSearchTerm && jsx(FormattedMessage, _extends({}, messages.searchLinkResults, {
66
+ values: {
67
+ count: items.length
68
+ },
69
+ "aria-live": "polite",
70
+ "aria-atomic": "true"
71
+ }))), jsx("ul", {
26
72
  id: id,
27
73
  role: role,
28
74
  css: listStyles,
29
- "aria-controls": ariaControls,
30
- "aria-labelledby": ariaLabelledBy,
75
+ "aria-controls": "fabric.smartcard.linkpicker.suggested.results",
76
+ "aria-labelledby": testIds.resultListTitle,
31
77
  "data-testid": testIds.searchResultList
32
78
  }, items.map((item, index) => jsx(LinkSearchListItem, {
33
79
  id: `${testIds.searchResultItem}-${index}`,
@@ -39,7 +85,7 @@ const LinkSearchList = ({
39
85
  onMouseLeave: onMouseLeave,
40
86
  onSelect: onSelect,
41
87
  key: item.objectId
42
- })));
88
+ }))));
43
89
  }
44
90
 
45
91
  if (isLoading) {
@@ -51,9 +97,9 @@ const LinkSearchList = ({
51
97
  }));
52
98
  }
53
99
 
54
- return jsx("div", {
100
+ return jsx("div", _extends({
101
+ ref: ref,
55
102
  css: listContainerStyles
56
- }, itemsContent, loadingContent);
57
- };
58
-
103
+ }, restProps), itemsContent, loadingContent);
104
+ });
59
105
  export default LinkSearchList;
@@ -0,0 +1,35 @@
1
+ /** @jsx jsx */
2
+ import { jsx } from '@emotion/react';
3
+ import EmptyState from '@atlaskit/empty-state';
4
+ import { useIntl, defineMessages } from 'react-intl-next';
5
+ import NoResultsSVG from './no-results-svg';
6
+ import { emptyStateWrapperStyles } from './styled';
7
+ export const messages = defineMessages({
8
+ noResults: {
9
+ id: 'fabric.linkPicker.search.noResults.heading',
10
+ defaultMessage: 'We couldn’t find anything matching your search.',
11
+ description: 'Heading message shown when a search has no results'
12
+ },
13
+ noResultsDescription: {
14
+ id: 'fabric.linkPicker.search.noResults.description',
15
+ defaultMessage: 'Try again with a different term.',
16
+ description: 'Describes possible action when a search returns no results'
17
+ }
18
+ });
19
+ export const testIds = {
20
+ emptyResultPage: 'link-search-no-results'
21
+ };
22
+
23
+ const NoResults = () => {
24
+ const intl = useIntl();
25
+ return jsx("div", {
26
+ css: emptyStateWrapperStyles
27
+ }, jsx(EmptyState, {
28
+ testId: testIds.emptyResultPage,
29
+ header: intl.formatMessage(messages.noResults),
30
+ description: intl.formatMessage(messages.noResultsDescription),
31
+ renderImage: () => jsx(NoResultsSVG, null)
32
+ }));
33
+ };
34
+
35
+ export default NoResults;
@@ -0,0 +1,6 @@
1
+ import { css } from '@emotion/react';
2
+ export const emptyStateWrapperStyles = css`
3
+ & p {
4
+ margin: 0;
5
+ }
6
+ `;
@@ -1,13 +1,34 @@
1
- import { css } from '@emotion/react';
1
+ import { css } from '@emotion/react'; // AFP-2532 TODO: Fix automatic suppressions below
2
+ // eslint-disable-next-line @atlassian/tangerine/import/entry-points
3
+
4
+ import { typography } from '@atlaskit/theme';
5
+ import { gridSize as getGridSize } from '@atlaskit/theme/constants';
6
+ const gridSize = getGridSize();
2
7
  export const listContainerStyles = css`
3
8
  padding-top: 0;
9
+ min-height: 80px;
10
+ margin-top: ${gridSize * 2}px;
11
+ margin-bottom: ${gridSize * 2}px;
12
+ flex-grow: 1;
13
+ display: flex;
14
+ flex-direction: column;
4
15
  `;
5
16
  export const spinnerContainerStyles = css`
6
17
  text-align: center;
7
18
  min-height: 80px;
8
- margin-top: 30px;
19
+ display: flex;
20
+ align-items: center;
21
+ justify-content: center;
22
+ flex-grow: 1;
9
23
  `;
10
24
  export const listStyles = css`
11
25
  padding: 0;
26
+ margin: 0;
12
27
  list-style: none;
28
+ `;
29
+ export const listTitleStyles = css`
30
+ ${typography.h100()}
31
+ text-transform: uppercase;
32
+ margin-top: 0;
33
+ margin-bottom: ${gridSize / 2}px;
13
34
  `;