@atlaskit/link-picker 1.30.14 → 1.32.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 (33) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/cjs/ui/index.js +1 -1
  3. package/dist/cjs/ui/link-picker/form-footer/index.js +35 -10
  4. package/dist/cjs/ui/link-picker/form-footer/utils.js +4 -1
  5. package/dist/cjs/ui/link-picker/index.js +40 -11
  6. package/dist/cjs/ui/link-picker/search-results/index.js +2 -0
  7. package/dist/cjs/ui/link-picker/search-results/link-search-list/index.js +3 -1
  8. package/dist/cjs/ui/messages-provider/lazy-messages-provider/utils/fetch-messages-for-locale.js +5 -15
  9. package/dist/es2019/ui/index.js +1 -1
  10. package/dist/es2019/ui/link-picker/form-footer/index.js +31 -9
  11. package/dist/es2019/ui/link-picker/form-footer/utils.js +4 -1
  12. package/dist/es2019/ui/link-picker/index.js +39 -11
  13. package/dist/es2019/ui/link-picker/search-results/index.js +2 -0
  14. package/dist/es2019/ui/link-picker/search-results/link-search-list/index.js +2 -0
  15. package/dist/es2019/ui/messages-provider/lazy-messages-provider/utils/fetch-messages-for-locale.js +0 -10
  16. package/dist/esm/ui/index.js +1 -1
  17. package/dist/esm/ui/link-picker/form-footer/index.js +35 -10
  18. package/dist/esm/ui/link-picker/form-footer/utils.js +4 -1
  19. package/dist/esm/ui/link-picker/index.js +40 -11
  20. package/dist/esm/ui/link-picker/search-results/index.js +2 -0
  21. package/dist/esm/ui/link-picker/search-results/link-search-list/index.js +3 -1
  22. package/dist/esm/ui/messages-provider/lazy-messages-provider/utils/fetch-messages-for-locale.js +5 -15
  23. package/dist/types/ui/link-picker/form-footer/index.d.ts +28 -1
  24. package/dist/types/ui/link-picker/form-footer/utils.d.ts +1 -1
  25. package/dist/types/ui/link-picker/index.d.ts +20 -0
  26. package/dist/types/ui/link-picker/search-results/index.d.ts +2 -1
  27. package/dist/types/ui/link-picker/search-results/link-search-list/index.d.ts +1 -0
  28. package/dist/types-ts4.5/ui/link-picker/form-footer/index.d.ts +28 -1
  29. package/dist/types-ts4.5/ui/link-picker/form-footer/utils.d.ts +1 -1
  30. package/dist/types-ts4.5/ui/link-picker/index.d.ts +20 -0
  31. package/dist/types-ts4.5/ui/link-picker/search-results/index.d.ts +2 -1
  32. package/dist/types-ts4.5/ui/link-picker/search-results/link-search-list/index.d.ts +1 -0
  33. package/package.json +6 -9
@@ -82,7 +82,9 @@ export const LinkPicker = withLinkPickerAnalyticsContext( /*#__PURE__*/memo(({
82
82
  url: initUrl,
83
83
  displayText: initDisplayText,
84
84
  hideDisplayText,
85
- featureFlags
85
+ featureFlags,
86
+ customMessages,
87
+ isSubmitting = false
86
88
  }) => {
87
89
  const {
88
90
  createAnalyticsEvent
@@ -126,6 +128,11 @@ export const LinkPicker = withLinkPickerAnalyticsContext( /*#__PURE__*/memo(({
126
128
  }
127
129
  }, [onContentResize, items, isLoadingResults, isActivePlugin, tabs]);
128
130
  const handleChangeUrl = useCallback(e => {
131
+ if (isSubmitting) {
132
+ // Prevent changing url while submitting
133
+ return;
134
+ }
135
+
129
136
  /** Any on change event is triggered by manual input or paste, so source is null */
130
137
  trackAttribute('linkFieldContentInputSource', null);
131
138
  dispatch({
@@ -133,7 +140,7 @@ export const LinkPicker = withLinkPickerAnalyticsContext( /*#__PURE__*/memo(({
133
140
  // If the last action was changing tabs, make sure we're now allowing recents to be hidden
134
141
  preventHidingRecents: false
135
142
  });
136
- }, [dispatch, trackAttribute]);
143
+ }, [dispatch, trackAttribute, isSubmitting]);
137
144
  const handleChangeText = useCallback(e => {
138
145
  dispatch({
139
146
  displayText: e.currentTarget.value
@@ -147,9 +154,13 @@ export const LinkPicker = withLinkPickerAnalyticsContext( /*#__PURE__*/memo(({
147
154
  });
148
155
  }, [dispatch]);
149
156
  const handleUrlClear = useCallback(() => {
157
+ if (isSubmitting) {
158
+ // Prevent clearing url while submitting
159
+ return;
160
+ }
150
161
  trackAttribute('linkFieldContentInputSource', null);
151
162
  handleClear('url');
152
- }, [trackAttribute, handleClear]);
163
+ }, [trackAttribute, handleClear, isSubmitting]);
153
164
  const handleInsert = useCallback((url, title, inputType) => {
154
165
  const event = createAnalyticsEvent(createEventPayload('ui.form.submitted.linkPicker', {}));
155
166
 
@@ -176,6 +187,10 @@ export const LinkPicker = withLinkPickerAnalyticsContext( /*#__PURE__*/memo(({
176
187
  }, consumerEvent);
177
188
  }, [displayText, onSubmit, state.url, createAnalyticsEvent, getAttributes]);
178
189
  const handleSelected = useCallback(objectId => {
190
+ if (isSubmitting) {
191
+ // Prevent changing selection while submitting
192
+ return;
193
+ }
179
194
  const selectedItem = items === null || items === void 0 ? void 0 : items.find(item => item.objectId === objectId);
180
195
  if (selectedItem) {
181
196
  const {
@@ -191,9 +206,13 @@ export const LinkPicker = withLinkPickerAnalyticsContext( /*#__PURE__*/memo(({
191
206
  trackAttribute('linkFieldContentInputSource', getDataSource(selectedItem, activePlugin));
192
207
  handleInsert(url, name, 'typeAhead');
193
208
  }
194
- }, [handleInsert, trackAttribute, items, activePlugin]);
209
+ }, [handleInsert, trackAttribute, items, activePlugin, isSubmitting]);
195
210
  const handleSubmit = useCallback(event => {
196
211
  event === null || event === void 0 ? void 0 : event.preventDefault();
212
+ if (isSubmitting) {
213
+ // Prevent submit while submitting
214
+ return;
215
+ }
197
216
  if (isSelectedItem && selectedItem) {
198
217
  return handleInsert(selectedItem.url, selectedItem.name, 'typeAhead');
199
218
  }
@@ -204,7 +223,7 @@ export const LinkPicker = withLinkPickerAnalyticsContext( /*#__PURE__*/memo(({
204
223
  return dispatch({
205
224
  invalidUrl: true
206
225
  });
207
- }, [dispatch, handleInsert, isSelectedItem, selectedItem, url]);
226
+ }, [dispatch, handleInsert, isSelectedItem, selectedItem, url, isSubmitting]);
208
227
  const handleTabChange = useCallback(activeTab => {
209
228
  var _plugins$activeTab$ta, _plugins$activeTab;
210
229
  dispatch({
@@ -220,6 +239,10 @@ export const LinkPicker = withLinkPickerAnalyticsContext( /*#__PURE__*/memo(({
220
239
  trackAttribute('tab', (_plugins$activeTab$ta = plugins === null || plugins === void 0 ? void 0 : (_plugins$activeTab = plugins[activeTab]) === null || _plugins$activeTab === void 0 ? void 0 : _plugins$activeTab.tabKey) !== null && _plugins$activeTab$ta !== void 0 ? _plugins$activeTab$ta : null);
221
240
  }, [dispatch, plugins, trackAttribute]);
222
241
  const handleSearchListOnChange = id => {
242
+ if (isSubmitting) {
243
+ // Prevent changing item while submitting
244
+ return;
245
+ }
223
246
  const index = items === null || items === void 0 ? void 0 : items.findIndex(item => item.objectId === id);
224
247
  if (typeof index === 'number') {
225
248
  const item = items === null || items === void 0 ? void 0 : items[index];
@@ -291,13 +314,13 @@ export const LinkPicker = withLinkPickerAnalyticsContext( /*#__PURE__*/memo(({
291
314
  delay: 250
292
315
  }), jsx(VisuallyHidden, {
293
316
  id: screenReaderDescriptionId
294
- }, jsx(FormattedMessage, messages.linkAriaLabel)), jsx(LinkInputField, {
317
+ }, customMessages !== null && customMessages !== void 0 && customMessages.linkAriaLabel ? jsx(FormattedMessage, customMessages.linkAriaLabel) : jsx(FormattedMessage, messages.linkAriaLabel)), jsx(LinkInputField, {
295
318
  role: "combobox",
296
319
  autoComplete: "off",
297
320
  name: "url",
298
321
  testId: testIds.urlInputField,
299
- label: intl.formatMessage(messages.linkLabel),
300
- placeholder: intl.formatMessage(messages.linkPlaceholder),
322
+ label: customMessages !== null && customMessages !== void 0 && customMessages.linkLabel ? intl.formatMessage(customMessages.linkLabel) : intl.formatMessage(messages.linkLabel),
323
+ placeholder: customMessages !== null && customMessages !== void 0 && customMessages.linkPlaceholder ? intl.formatMessage(customMessages === null || customMessages === void 0 ? void 0 : customMessages.linkPlaceholder) : intl.formatMessage(messages.linkPlaceholder),
301
324
  value: url,
302
325
  autoFocus: true,
303
326
  clearLabel: intl.formatMessage(formMessages.clearLink),
@@ -306,6 +329,7 @@ export const LinkPicker = withLinkPickerAnalyticsContext( /*#__PURE__*/memo(({
306
329
  "aria-controls": linkSearchListId,
307
330
  "aria-activedescendant": ariaActiveDescendant,
308
331
  "aria-describedby": screenReaderDescriptionId,
332
+ "aria-readonly": isSubmitting,
309
333
  error: invalidUrl ? intl.formatMessage(formMessages.linkInvalid) : null,
310
334
  spotlightTargetName: "link-picker-search-field-spotlight-target",
311
335
  onClear: handleUrlClear,
@@ -316,9 +340,10 @@ export const LinkPicker = withLinkPickerAnalyticsContext( /*#__PURE__*/memo(({
316
340
  name: "displayText",
317
341
  testId: testIds.textInputField,
318
342
  value: displayText,
319
- label: intl.formatMessage(linkTextMessages.linkTextLabel),
320
- placeholder: intl.formatMessage(linkTextMessages.linkTextPlaceholder),
343
+ label: customMessages !== null && customMessages !== void 0 && customMessages.linkTextLabel ? intl.formatMessage(customMessages.linkTextLabel) : intl.formatMessage(linkTextMessages.linkTextLabel),
344
+ placeholder: customMessages !== null && customMessages !== void 0 && customMessages.linkTextPlaceholder ? intl.formatMessage(customMessages === null || customMessages === void 0 ? void 0 : customMessages.linkTextPlaceholder) : intl.formatMessage(linkTextMessages.linkTextPlaceholder),
321
345
  clearLabel: intl.formatMessage(linkTextMessages.clearLinkText),
346
+ readOnly: isSubmitting,
322
347
  onClear: handleClear,
323
348
  onChange: handleChangeText
324
349
  }), !!queryState && (isLoadingPlugins || isActivePlugin) && jsx(SearchResults, {
@@ -327,6 +352,7 @@ export const LinkPicker = withLinkPickerAnalyticsContext( /*#__PURE__*/memo(({
327
352
  activePlugin: activePlugin,
328
353
  isLoadingResults: isLoadingResults,
329
354
  isLoadingPlugins: isLoadingPlugins,
355
+ isSubmitting: isSubmitting,
330
356
  linkSearchListId: linkSearchListId,
331
357
  error: error,
332
358
  featureFlags: featureFlags,
@@ -344,6 +370,7 @@ export const LinkPicker = withLinkPickerAnalyticsContext( /*#__PURE__*/memo(({
344
370
  items: items
345
371
  /** If the results section appears to be loading, impact whether the submit button is disabled */,
346
372
  isLoading: isLoadingResults || !!isLoadingPlugins,
373
+ isSubmitting: isSubmitting,
347
374
  queryState: queryState,
348
375
  url: url,
349
376
  isEditing: isEditing,
@@ -352,6 +379,7 @@ export const LinkPicker = withLinkPickerAnalyticsContext( /*#__PURE__*/memo(({
352
379
  css: !queryState || !(plugins !== null && plugins !== void 0 && plugins.length) ? formFooterMargin : undefined
353
380
  /* Show the feature discovery pulse when we're on the Jira tab, we haven't started typing a url and
354
381
  the feature flag is enabled */,
355
- createFeatureDiscovery: (activePlugin === null || activePlugin === void 0 ? void 0 : activePlugin.tabKey) === 'jira' && allowCreateFeatureDiscovery && getBooleanFF('platform.linking-platform.link-picker.enable-jira-create')
382
+ createFeatureDiscovery: (activePlugin === null || activePlugin === void 0 ? void 0 : activePlugin.tabKey) === 'jira' && allowCreateFeatureDiscovery && getBooleanFF('platform.linking-platform.link-picker.enable-jira-create'),
383
+ customSubmitButtonLabel: customMessages !== null && customMessages !== void 0 && customMessages.submitButtonLabel ? customMessages.submitButtonLabel : undefined
356
384
  }));
357
385
  }));
@@ -24,6 +24,7 @@ export const SearchResults = ({
24
24
  activePlugin,
25
25
  isLoadingPlugins,
26
26
  isLoadingResults,
27
+ isSubmitting,
27
28
  handleTabChange,
28
29
  handleSearchListOnChange,
29
30
  featureFlags,
@@ -65,6 +66,7 @@ export const SearchResults = ({
65
66
  })), !error && jsx(LinkSearchList, {
66
67
  id: linkSearchListId,
67
68
  role: "listbox",
69
+ ariaReadOnly: isSubmitting,
68
70
  items: items,
69
71
  isLoading: isLoadingResults,
70
72
  selectedIndex: selectedIndex,
@@ -48,6 +48,7 @@ export const LinkSearchList = /*#__PURE__*/forwardRef(({
48
48
  isLoading,
49
49
  ariaControls,
50
50
  ariaLabelledBy,
51
+ ariaReadOnly,
51
52
  role,
52
53
  id,
53
54
  hasSearchTerm,
@@ -124,6 +125,7 @@ export const LinkSearchList = /*#__PURE__*/forwardRef(({
124
125
  css: listStyles,
125
126
  "aria-controls": "fabric.smartcard.linkpicker.suggested.results",
126
127
  "aria-labelledby": testIds.resultListTitle,
128
+ "aria-readonly": ariaReadOnly,
127
129
  "data-testid": testIds.searchResultList
128
130
  }, items.map((item, index) => jsx(LinkSearchListItem, {
129
131
  id: `${testIds.searchResultItem}-${index}`,
@@ -1,5 +1,3 @@
1
- import { getBooleanFF } from '@atlaskit/platform-feature-flags';
2
- import messages from '../../../../i18n/en';
3
1
  export const fetchMessagesForLocale = async locale => {
4
2
  try {
5
3
  const messages = await import( /* webpackChunkName: "@atlaskit-internal_link-picker-i18n-[request]" */`../../../../i18n/${locale.replace('-', '_')}`);
@@ -14,12 +12,4 @@ export const fetchMessagesForLocale = async locale => {
14
12
  } catch (e) {
15
13
  // ignore
16
14
  }
17
- if (getBooleanFF('platform.linking-platform.link-create.tmp-fix-translations')) {
18
- return;
19
- }
20
-
21
- /**
22
- * English bundled by default as this is the majority of users
23
- */
24
- return messages;
25
15
  };
@@ -17,7 +17,7 @@ export var testIds = {
17
17
  };
18
18
  export var PACKAGE_DATA = {
19
19
  packageName: "@atlaskit/link-picker" || '',
20
- packageVersion: "1.30.14" || '',
20
+ packageVersion: "1.32.0" || '',
21
21
  componentName: COMPONENT_NAME,
22
22
  source: COMPONENT_NAME
23
23
  };
@@ -1,17 +1,20 @@
1
1
  import _extends from "@babel/runtime/helpers/extends";
2
2
  import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
3
- var _excluded = ["isLoading", "error", "url", "queryState", "items", "isEditing", "onCancel", "action", "createFeatureDiscovery"];
3
+ var _excluded = ["isLoading", "isSubmitting", "error", "url", "queryState", "items", "isEditing", "onCancel", "action", "createFeatureDiscovery", "customSubmitButtonLabel"];
4
4
  /** @jsx jsx */
5
- import { memo } from 'react';
5
+ import { memo, useMemo } from 'react';
6
6
  import { jsx } from '@emotion/react';
7
7
  import { defineMessages, useIntl } from 'react-intl-next';
8
+ import uuid from 'uuid';
8
9
  import Button, { ButtonGroup } from '@atlaskit/button';
10
+ import LoadingButton from '@atlaskit/button/loading-button';
9
11
  import EditorAddIcon from '@atlaskit/icon/glyph/editor/add';
12
+ import VisuallyHidden from '@atlaskit/visually-hidden';
10
13
  import { UnauthenticatedError } from '../../../common/utils/errors';
11
14
  import FeatureDiscovery from './feature-discovery';
12
15
  import { formFooterActionStyles, formFooterStyles } from './styled';
13
16
  import { checkSubmitDisabled } from './utils';
14
- var messages = defineMessages({
17
+ export var messages = defineMessages({
15
18
  cancelButton: {
16
19
  id: 'fabric.linkPicker.button.cancel',
17
20
  defaultMessage: 'Cancel',
@@ -26,17 +29,25 @@ var messages = defineMessages({
26
29
  id: 'fabric.linkPicker.button.insert',
27
30
  defaultMessage: 'Insert',
28
31
  description: 'Button to insert searched or selected link'
32
+ },
33
+ submittingStatusMessage: {
34
+ id: 'fabric.linkPicker.status.submitting',
35
+ defaultMessage: 'Submitting',
36
+ description: 'Accessibility text to indicate the form has been submitted, and submission is in-progress'
29
37
  }
30
38
  });
31
39
  export var testIds = {
32
40
  insertButton: 'link-picker-insert-button',
33
41
  cancelButton: 'link-picker-cancel-button',
34
42
  actionButton: 'link-picker-action-button',
43
+ submitStatusA11yIndicator: 'link-picker-submit-status-a11y-indicator',
35
44
  /** Feature discovery for action button (css pulse) */
36
45
  actionButtonDiscovery: 'link-picker-action-button-discovery'
37
46
  };
38
47
  export var FormFooter = /*#__PURE__*/memo(function (_ref) {
39
48
  var isLoading = _ref.isLoading,
49
+ _ref$isSubmitting = _ref.isSubmitting,
50
+ isSubmitting = _ref$isSubmitting === void 0 ? false : _ref$isSubmitting,
40
51
  error = _ref.error,
41
52
  url = _ref.url,
42
53
  queryState = _ref.queryState,
@@ -46,12 +57,16 @@ export var FormFooter = /*#__PURE__*/memo(function (_ref) {
46
57
  action = _ref.action,
47
58
  _ref$createFeatureDis = _ref.createFeatureDiscovery,
48
59
  createFeatureDiscovery = _ref$createFeatureDis === void 0 ? false : _ref$createFeatureDis,
60
+ customSubmitButtonLabel = _ref.customSubmitButtonLabel,
49
61
  restProps = _objectWithoutProperties(_ref, _excluded);
50
62
  var intl = useIntl();
63
+ var submitMessageId = useMemo(function () {
64
+ return uuid();
65
+ }, []);
51
66
  if (error && error instanceof UnauthenticatedError) {
52
67
  return null;
53
68
  }
54
- var isSubmitDisabled = checkSubmitDisabled(isLoading, error, url, queryState, items);
69
+ var isSubmitDisabled = checkSubmitDisabled(isLoading, isSubmitting, error, url, queryState, items);
55
70
  var insertButtonMsg = isEditing ? messages.saveButton : messages.insertButton;
56
71
  var createButton = function createButton(pluginAction) {
57
72
  return jsx(Button, {
@@ -61,23 +76,33 @@ export var FormFooter = /*#__PURE__*/memo(function (_ref) {
61
76
  iconBefore: jsx(EditorAddIcon, {
62
77
  label: "",
63
78
  size: "medium"
64
- })
79
+ }),
80
+ isDisabled: isSubmitting,
81
+ "aria-labelledby": isSubmitting ? submitMessageId : undefined
65
82
  }, typeof pluginAction.label === 'string' ? pluginAction.label : intl.formatMessage(pluginAction.label));
66
83
  };
67
84
  return jsx("footer", _extends({
68
85
  css: formFooterStyles
69
- }, restProps), action && jsx("div", {
86
+ }, restProps), isSubmitting && jsx(VisuallyHidden, {
87
+ role: "status",
88
+ id: submitMessageId,
89
+ testId: testIds.submitStatusA11yIndicator
90
+ }, intl.formatMessage(messages.submittingStatusMessage)), action && jsx("div", {
70
91
  css: formFooterActionStyles
71
92
  }, createFeatureDiscovery ? jsx(FeatureDiscovery, {
72
93
  testId: testIds.actionButtonDiscovery
73
94
  }, createButton(action)) : createButton(action)), jsx(ButtonGroup, null, jsx(Button, {
74
95
  appearance: "subtle",
75
96
  onClick: onCancel,
76
- testId: testIds.cancelButton
77
- }, intl.formatMessage(messages.cancelButton)), jsx(Button, {
97
+ testId: testIds.cancelButton,
98
+ isDisabled: isSubmitting,
99
+ "aria-labelledby": isSubmitting ? submitMessageId : undefined
100
+ }, intl.formatMessage(messages.cancelButton)), jsx(LoadingButton, {
78
101
  type: "submit",
79
102
  appearance: "primary",
80
103
  testId: testIds.insertButton,
81
- isDisabled: isSubmitDisabled
82
- }, intl.formatMessage(insertButtonMsg))));
104
+ isDisabled: isSubmitDisabled,
105
+ "aria-labelledby": isSubmitting ? submitMessageId : undefined,
106
+ isLoading: isSubmitting
107
+ }, customSubmitButtonLabel ? intl.formatMessage(customSubmitButtonLabel) : intl.formatMessage(insertButtonMsg))));
83
108
  });
@@ -1,5 +1,5 @@
1
1
  import { normalizeUrl } from '@atlaskit/linking-common/url';
2
- export var checkSubmitDisabled = function checkSubmitDisabled(isLoading, error, url, queryState, items) {
2
+ export var checkSubmitDisabled = function checkSubmitDisabled(isLoading, isSubmitting, error, url, queryState, items) {
3
3
  /*
4
4
  * Enable insert when search term is a valid url and it can be normalized
5
5
  * Need to explicitly enable it here otherwise next condition could meet
@@ -7,6 +7,9 @@ export var checkSubmitDisabled = function checkSubmitDisabled(isLoading, error,
7
7
  * This should effectively be the validation function for the form, ie if the form
8
8
  * could be submitted, then it should not be disabled
9
9
  */
10
+ if (isSubmitting) {
11
+ return true;
12
+ }
10
13
  if (url && normalizeUrl(url)) {
11
14
  return false;
12
15
  }
@@ -79,7 +79,10 @@ export var LinkPicker = withLinkPickerAnalyticsContext( /*#__PURE__*/memo(functi
79
79
  initUrl = _ref.url,
80
80
  initDisplayText = _ref.displayText,
81
81
  hideDisplayText = _ref.hideDisplayText,
82
- featureFlags = _ref.featureFlags;
82
+ featureFlags = _ref.featureFlags,
83
+ customMessages = _ref.customMessages,
84
+ _ref$isSubmitting = _ref.isSubmitting,
85
+ isSubmitting = _ref$isSubmitting === void 0 ? false : _ref$isSubmitting;
83
86
  var _useAnalyticsEvents = useAnalyticsEvents(),
84
87
  createAnalyticsEvent = _useAnalyticsEvents.createAnalyticsEvent;
85
88
  var _useReducer = useReducer(reducer, _objectSpread(_objectSpread({}, initState), {}, {
@@ -119,6 +122,11 @@ export var LinkPicker = withLinkPickerAnalyticsContext( /*#__PURE__*/memo(functi
119
122
  }
120
123
  }, [onContentResize, items, isLoadingResults, isActivePlugin, tabs]);
121
124
  var handleChangeUrl = useCallback(function (e) {
125
+ if (isSubmitting) {
126
+ // Prevent changing url while submitting
127
+ return;
128
+ }
129
+
122
130
  /** Any on change event is triggered by manual input or paste, so source is null */
123
131
  trackAttribute('linkFieldContentInputSource', null);
124
132
  dispatch({
@@ -126,7 +134,7 @@ export var LinkPicker = withLinkPickerAnalyticsContext( /*#__PURE__*/memo(functi
126
134
  // If the last action was changing tabs, make sure we're now allowing recents to be hidden
127
135
  preventHidingRecents: false
128
136
  });
129
- }, [dispatch, trackAttribute]);
137
+ }, [dispatch, trackAttribute, isSubmitting]);
130
138
  var handleChangeText = useCallback(function (e) {
131
139
  dispatch({
132
140
  displayText: e.currentTarget.value
@@ -139,9 +147,13 @@ export var LinkPicker = withLinkPickerAnalyticsContext( /*#__PURE__*/memo(functi
139
147
  }, field, ''));
140
148
  }, [dispatch]);
141
149
  var handleUrlClear = useCallback(function () {
150
+ if (isSubmitting) {
151
+ // Prevent clearing url while submitting
152
+ return;
153
+ }
142
154
  trackAttribute('linkFieldContentInputSource', null);
143
155
  handleClear('url');
144
- }, [trackAttribute, handleClear]);
156
+ }, [trackAttribute, handleClear, isSubmitting]);
145
157
  var handleInsert = useCallback(function (url, title, inputType) {
146
158
  var event = createAnalyticsEvent(createEventPayload('ui.form.submitted.linkPicker', {}));
147
159
 
@@ -167,6 +179,10 @@ export var LinkPicker = withLinkPickerAnalyticsContext( /*#__PURE__*/memo(functi
167
179
  } : {}), consumerEvent);
168
180
  }, [displayText, onSubmit, state.url, createAnalyticsEvent, getAttributes]);
169
181
  var handleSelected = useCallback(function (objectId) {
182
+ if (isSubmitting) {
183
+ // Prevent changing selection while submitting
184
+ return;
185
+ }
170
186
  var selectedItem = items === null || items === void 0 ? void 0 : items.find(function (item) {
171
187
  return item.objectId === objectId;
172
188
  });
@@ -182,9 +198,13 @@ export var LinkPicker = withLinkPickerAnalyticsContext( /*#__PURE__*/memo(functi
182
198
  trackAttribute('linkFieldContentInputSource', getDataSource(selectedItem, activePlugin));
183
199
  handleInsert(_url, name, 'typeAhead');
184
200
  }
185
- }, [handleInsert, trackAttribute, items, activePlugin]);
201
+ }, [handleInsert, trackAttribute, items, activePlugin, isSubmitting]);
186
202
  var handleSubmit = useCallback(function (event) {
187
203
  event === null || event === void 0 || event.preventDefault();
204
+ if (isSubmitting) {
205
+ // Prevent submit while submitting
206
+ return;
207
+ }
188
208
  if (isSelectedItem && selectedItem) {
189
209
  return handleInsert(selectedItem.url, selectedItem.name, 'typeAhead');
190
210
  }
@@ -195,7 +215,7 @@ export var LinkPicker = withLinkPickerAnalyticsContext( /*#__PURE__*/memo(functi
195
215
  return dispatch({
196
216
  invalidUrl: true
197
217
  });
198
- }, [dispatch, handleInsert, isSelectedItem, selectedItem, url]);
218
+ }, [dispatch, handleInsert, isSelectedItem, selectedItem, url, isSubmitting]);
199
219
  var handleTabChange = useCallback(function (activeTab) {
200
220
  var _plugins$activeTab$ta, _plugins$activeTab;
201
221
  dispatch({
@@ -211,6 +231,10 @@ export var LinkPicker = withLinkPickerAnalyticsContext( /*#__PURE__*/memo(functi
211
231
  trackAttribute('tab', (_plugins$activeTab$ta = plugins === null || plugins === void 0 || (_plugins$activeTab = plugins[activeTab]) === null || _plugins$activeTab === void 0 ? void 0 : _plugins$activeTab.tabKey) !== null && _plugins$activeTab$ta !== void 0 ? _plugins$activeTab$ta : null);
212
232
  }, [dispatch, plugins, trackAttribute]);
213
233
  var handleSearchListOnChange = function handleSearchListOnChange(id) {
234
+ if (isSubmitting) {
235
+ // Prevent changing item while submitting
236
+ return;
237
+ }
214
238
  var index = items === null || items === void 0 ? void 0 : items.findIndex(function (item) {
215
239
  return item.objectId === id;
216
240
  });
@@ -284,13 +308,13 @@ export var LinkPicker = withLinkPickerAnalyticsContext( /*#__PURE__*/memo(functi
284
308
  delay: 250
285
309
  }), jsx(VisuallyHidden, {
286
310
  id: screenReaderDescriptionId
287
- }, jsx(FormattedMessage, messages.linkAriaLabel)), jsx(LinkInputField, {
311
+ }, customMessages !== null && customMessages !== void 0 && customMessages.linkAriaLabel ? jsx(FormattedMessage, customMessages.linkAriaLabel) : jsx(FormattedMessage, messages.linkAriaLabel)), jsx(LinkInputField, {
288
312
  role: "combobox",
289
313
  autoComplete: "off",
290
314
  name: "url",
291
315
  testId: testIds.urlInputField,
292
- label: intl.formatMessage(messages.linkLabel),
293
- placeholder: intl.formatMessage(messages.linkPlaceholder),
316
+ label: customMessages !== null && customMessages !== void 0 && customMessages.linkLabel ? intl.formatMessage(customMessages.linkLabel) : intl.formatMessage(messages.linkLabel),
317
+ placeholder: customMessages !== null && customMessages !== void 0 && customMessages.linkPlaceholder ? intl.formatMessage(customMessages === null || customMessages === void 0 ? void 0 : customMessages.linkPlaceholder) : intl.formatMessage(messages.linkPlaceholder),
294
318
  value: url,
295
319
  autoFocus: true,
296
320
  clearLabel: intl.formatMessage(formMessages.clearLink),
@@ -299,6 +323,7 @@ export var LinkPicker = withLinkPickerAnalyticsContext( /*#__PURE__*/memo(functi
299
323
  "aria-controls": linkSearchListId,
300
324
  "aria-activedescendant": ariaActiveDescendant,
301
325
  "aria-describedby": screenReaderDescriptionId,
326
+ "aria-readonly": isSubmitting,
302
327
  error: invalidUrl ? intl.formatMessage(formMessages.linkInvalid) : null,
303
328
  spotlightTargetName: "link-picker-search-field-spotlight-target",
304
329
  onClear: handleUrlClear,
@@ -309,9 +334,10 @@ export var LinkPicker = withLinkPickerAnalyticsContext( /*#__PURE__*/memo(functi
309
334
  name: "displayText",
310
335
  testId: testIds.textInputField,
311
336
  value: displayText,
312
- label: intl.formatMessage(linkTextMessages.linkTextLabel),
313
- placeholder: intl.formatMessage(linkTextMessages.linkTextPlaceholder),
337
+ label: customMessages !== null && customMessages !== void 0 && customMessages.linkTextLabel ? intl.formatMessage(customMessages.linkTextLabel) : intl.formatMessage(linkTextMessages.linkTextLabel),
338
+ placeholder: customMessages !== null && customMessages !== void 0 && customMessages.linkTextPlaceholder ? intl.formatMessage(customMessages === null || customMessages === void 0 ? void 0 : customMessages.linkTextPlaceholder) : intl.formatMessage(linkTextMessages.linkTextPlaceholder),
314
339
  clearLabel: intl.formatMessage(linkTextMessages.clearLinkText),
340
+ readOnly: isSubmitting,
315
341
  onClear: handleClear,
316
342
  onChange: handleChangeText
317
343
  }), !!queryState && (isLoadingPlugins || isActivePlugin) && jsx(SearchResults, {
@@ -320,6 +346,7 @@ export var LinkPicker = withLinkPickerAnalyticsContext( /*#__PURE__*/memo(functi
320
346
  activePlugin: activePlugin,
321
347
  isLoadingResults: isLoadingResults,
322
348
  isLoadingPlugins: isLoadingPlugins,
349
+ isSubmitting: isSubmitting,
323
350
  linkSearchListId: linkSearchListId,
324
351
  error: error,
325
352
  featureFlags: featureFlags,
@@ -337,6 +364,7 @@ export var LinkPicker = withLinkPickerAnalyticsContext( /*#__PURE__*/memo(functi
337
364
  items: items
338
365
  /** If the results section appears to be loading, impact whether the submit button is disabled */,
339
366
  isLoading: isLoadingResults || !!isLoadingPlugins,
367
+ isSubmitting: isSubmitting,
340
368
  queryState: queryState,
341
369
  url: url,
342
370
  isEditing: isEditing,
@@ -345,6 +373,7 @@ export var LinkPicker = withLinkPickerAnalyticsContext( /*#__PURE__*/memo(functi
345
373
  css: !queryState || !(plugins !== null && plugins !== void 0 && plugins.length) ? formFooterMargin : undefined
346
374
  /* Show the feature discovery pulse when we're on the Jira tab, we haven't started typing a url and
347
375
  the feature flag is enabled */,
348
- createFeatureDiscovery: (activePlugin === null || activePlugin === void 0 ? void 0 : activePlugin.tabKey) === 'jira' && allowCreateFeatureDiscovery && getBooleanFF('platform.linking-platform.link-picker.enable-jira-create')
376
+ createFeatureDiscovery: (activePlugin === null || activePlugin === void 0 ? void 0 : activePlugin.tabKey) === 'jira' && allowCreateFeatureDiscovery && getBooleanFF('platform.linking-platform.link-picker.enable-jira-create'),
377
+ customSubmitButtonLabel: customMessages !== null && customMessages !== void 0 && customMessages.submitButtonLabel ? customMessages.submitButtonLabel : undefined
349
378
  }));
350
379
  }));
@@ -26,6 +26,7 @@ export var SearchResults = function SearchResults(_ref) {
26
26
  activePlugin = _ref.activePlugin,
27
27
  isLoadingPlugins = _ref.isLoadingPlugins,
28
28
  isLoadingResults = _ref.isLoadingResults,
29
+ isSubmitting = _ref.isSubmitting,
29
30
  handleTabChange = _ref.handleTabChange,
30
31
  handleSearchListOnChange = _ref.handleSearchListOnChange,
31
32
  featureFlags = _ref.featureFlags,
@@ -67,6 +68,7 @@ export var SearchResults = function SearchResults(_ref) {
67
68
  })), !error && jsx(LinkSearchList, {
68
69
  id: linkSearchListId,
69
70
  role: "listbox",
71
+ ariaReadOnly: isSubmitting,
70
72
  items: items,
71
73
  isLoading: isLoadingResults,
72
74
  selectedIndex: selectedIndex,
@@ -1,7 +1,7 @@
1
1
  import _extends from "@babel/runtime/helpers/extends";
2
2
  import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
3
3
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
4
- var _excluded = ["onChange", "onSelect", "onKeyDown", "items", "activeIndex", "selectedIndex", "isLoading", "ariaControls", "ariaLabelledBy", "role", "id", "hasSearchTerm", "activePlugin"];
4
+ var _excluded = ["onChange", "onSelect", "onKeyDown", "items", "activeIndex", "selectedIndex", "isLoading", "ariaControls", "ariaLabelledBy", "ariaReadOnly", "role", "id", "hasSearchTerm", "activePlugin"];
5
5
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
6
6
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
7
7
  /** @jsx jsx */
@@ -51,6 +51,7 @@ export var LinkSearchList = /*#__PURE__*/forwardRef(function (_ref, ref) {
51
51
  isLoading = _ref.isLoading,
52
52
  ariaControls = _ref.ariaControls,
53
53
  ariaLabelledBy = _ref.ariaLabelledBy,
54
+ ariaReadOnly = _ref.ariaReadOnly,
54
55
  role = _ref.role,
55
56
  id = _ref.id,
56
57
  hasSearchTerm = _ref.hasSearchTerm,
@@ -126,6 +127,7 @@ export var LinkSearchList = /*#__PURE__*/forwardRef(function (_ref, ref) {
126
127
  css: listStyles,
127
128
  "aria-controls": "fabric.smartcard.linkpicker.suggested.results",
128
129
  "aria-labelledby": testIds.resultListTitle,
130
+ "aria-readonly": ariaReadOnly,
129
131
  "data-testid": testIds.searchResultList
130
132
  }, items.map(function (item, index) {
131
133
  return jsx(LinkSearchListItem, {
@@ -1,10 +1,8 @@
1
1
  import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
2
2
  import _regeneratorRuntime from "@babel/runtime/regenerator";
3
- import { getBooleanFF } from '@atlaskit/platform-feature-flags';
4
- import messages from '../../../../i18n/en';
5
3
  export var fetchMessagesForLocale = /*#__PURE__*/function () {
6
4
  var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(locale) {
7
- var _messages, parentLocale, _messages2;
5
+ var messages, parentLocale, _messages;
8
6
  return _regeneratorRuntime.wrap(function _callee$(_context) {
9
7
  while (1) switch (_context.prev = _context.next) {
10
8
  case 0:
@@ -12,8 +10,8 @@ export var fetchMessagesForLocale = /*#__PURE__*/function () {
12
10
  _context.next = 3;
13
11
  return import( /* webpackChunkName: "@atlaskit-internal_link-picker-i18n-[request]" */"../../../../i18n/".concat(locale.replace('-', '_')));
14
12
  case 3:
15
- _messages = _context.sent;
16
- return _context.abrupt("return", _messages.default);
13
+ messages = _context.sent;
14
+ return _context.abrupt("return", messages.default);
17
15
  case 7:
18
16
  _context.prev = 7;
19
17
  _context.t0 = _context["catch"](0);
@@ -23,20 +21,12 @@ export var fetchMessagesForLocale = /*#__PURE__*/function () {
23
21
  _context.next = 13;
24
22
  return import( /* webpackChunkName: "@atlaskit-internal_link-picker-i18n-[request]" */"../../../../i18n/".concat(parentLocale));
25
23
  case 13:
26
- _messages2 = _context.sent;
27
- return _context.abrupt("return", _messages2.default);
24
+ _messages = _context.sent;
25
+ return _context.abrupt("return", _messages.default);
28
26
  case 17:
29
27
  _context.prev = 17;
30
28
  _context.t1 = _context["catch"](9);
31
29
  case 19:
32
- if (!getBooleanFF('platform.linking-platform.link-create.tmp-fix-translations')) {
33
- _context.next = 21;
34
- break;
35
- }
36
- return _context.abrupt("return");
37
- case 21:
38
- return _context.abrupt("return", messages);
39
- case 22:
40
30
  case "end":
41
31
  return _context.stop();
42
32
  }
@@ -1,16 +1,42 @@
1
1
  /// <reference types="react" />
2
2
  import { jsx } from '@emotion/react';
3
+ import { MessageDescriptor } from 'react-intl-next';
3
4
  import { LinkPickerPluginAction, LinkPickerState, LinkSearchListItemData } from '../../../common/types';
5
+ export declare const messages: {
6
+ cancelButton: {
7
+ id: string;
8
+ defaultMessage: string;
9
+ description: string;
10
+ };
11
+ saveButton: {
12
+ id: string;
13
+ defaultMessage: string;
14
+ description: string;
15
+ };
16
+ insertButton: {
17
+ id: string;
18
+ defaultMessage: string;
19
+ description: string;
20
+ };
21
+ submittingStatusMessage: {
22
+ id: string;
23
+ defaultMessage: string;
24
+ description: string;
25
+ };
26
+ };
4
27
  export declare const testIds: {
5
28
  readonly insertButton: "link-picker-insert-button";
6
29
  readonly cancelButton: "link-picker-cancel-button";
7
30
  readonly actionButton: "link-picker-action-button";
31
+ readonly submitStatusA11yIndicator: "link-picker-submit-status-a11y-indicator";
8
32
  /** Feature discovery for action button (css pulse) */
9
33
  readonly actionButtonDiscovery: "link-picker-action-button-discovery";
10
34
  };
11
35
  interface FormFooterProps extends React.HTMLAttributes<HTMLElement> {
12
36
  /** If the results section appears to be loading, impact whether the submit button is disabled */
13
37
  isLoading: boolean;
38
+ /** Controls showing a "submission in-progres" UX */
39
+ isSubmitting?: boolean;
14
40
  error: unknown | null;
15
41
  url: string;
16
42
  queryState: LinkPickerState | null;
@@ -19,6 +45,7 @@ interface FormFooterProps extends React.HTMLAttributes<HTMLElement> {
19
45
  onCancel?: () => void;
20
46
  action?: LinkPickerPluginAction;
21
47
  createFeatureDiscovery?: boolean;
48
+ customSubmitButtonLabel?: MessageDescriptor;
22
49
  }
23
- export declare const FormFooter: import("react").MemoExoticComponent<({ isLoading, error, url, queryState, items, isEditing, onCancel, action, createFeatureDiscovery, ...restProps }: FormFooterProps) => jsx.JSX.Element | null>;
50
+ export declare const FormFooter: import("react").MemoExoticComponent<({ isLoading, isSubmitting, error, url, queryState, items, isEditing, onCancel, action, createFeatureDiscovery, customSubmitButtonLabel, ...restProps }: FormFooterProps) => jsx.JSX.Element | null>;
24
51
  export {};
@@ -1,2 +1,2 @@
1
1
  import { LinkPickerState, LinkSearchListItemData } from '../../../common/types';
2
- export declare const checkSubmitDisabled: (isLoading: boolean, error: unknown | null, url: string, queryState: LinkPickerState | null, items: LinkSearchListItemData[] | null) => boolean;
2
+ export declare const checkSubmitDisabled: (isLoading: boolean, isSubmitting: boolean, error: unknown | null, url: string, queryState: LinkPickerState | null, items: LinkSearchListItemData[] | null) => boolean;