@atlaskit/link-picker 1.6.1 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/dist/cjs/analytics.codegen.js +28 -0
- package/dist/cjs/common/constants.js +10 -0
- package/dist/cjs/{ui/error-boundary-fallback → common}/generic-error-svg/index.js +0 -0
- package/dist/cjs/{ui/error-boundary-fallback → common}/generic-error-svg/styled.js +0 -0
- package/dist/cjs/services/use-plugins/index.js +32 -35
- package/dist/cjs/services/use-search-query/index.js +41 -0
- package/dist/cjs/ui/error-boundary-fallback/index.js +1 -1
- package/dist/cjs/ui/index.js +4 -4
- package/dist/cjs/ui/link-picker/index.js +74 -46
- package/dist/cjs/ui/link-picker/link-search-error/index.js +27 -0
- package/dist/cjs/ui/link-picker/messages.js +10 -0
- package/dist/cjs/ui/link-picker/text-input/index.js +4 -10
- package/dist/cjs/ui/link-picker/url.js +0 -5
- package/dist/cjs/version.json +1 -1
- package/dist/es2019/analytics.codegen.js +20 -0
- package/dist/es2019/common/constants.js +2 -0
- package/dist/es2019/{ui/error-boundary-fallback → common}/generic-error-svg/index.js +0 -0
- package/dist/es2019/{ui/error-boundary-fallback → common}/generic-error-svg/styled.js +0 -0
- package/dist/es2019/services/use-plugins/index.js +28 -38
- package/dist/es2019/services/use-search-query/index.js +32 -0
- package/dist/es2019/ui/error-boundary-fallback/index.js +1 -1
- package/dist/es2019/ui/index.js +1 -2
- package/dist/es2019/ui/link-picker/index.js +65 -45
- package/dist/es2019/ui/link-picker/link-search-error/index.js +10 -0
- package/dist/es2019/ui/link-picker/messages.js +10 -0
- package/dist/es2019/ui/link-picker/text-input/index.js +3 -9
- package/dist/es2019/ui/link-picker/url.js +0 -5
- package/dist/es2019/version.json +1 -1
- package/dist/esm/analytics.codegen.js +20 -0
- package/dist/esm/common/constants.js +2 -0
- package/dist/esm/{ui/error-boundary-fallback → common}/generic-error-svg/index.js +0 -0
- package/dist/esm/{ui/error-boundary-fallback → common}/generic-error-svg/styled.js +0 -0
- package/dist/esm/services/use-plugins/index.js +33 -35
- package/dist/esm/services/use-search-query/index.js +32 -0
- package/dist/esm/ui/error-boundary-fallback/index.js +1 -1
- package/dist/esm/ui/index.js +1 -2
- package/dist/esm/ui/link-picker/index.js +67 -45
- package/dist/esm/ui/link-picker/link-search-error/index.js +14 -0
- package/dist/esm/ui/link-picker/messages.js +10 -0
- package/dist/esm/ui/link-picker/text-input/index.js +4 -10
- package/dist/esm/ui/link-picker/url.js +0 -5
- package/dist/esm/version.json +1 -1
- package/dist/types/analytics.codegen.d.ts +20 -0
- package/dist/types/common/constants.d.ts +2 -0
- package/dist/types/{ui/error-boundary-fallback → common}/generic-error-svg/index.d.ts +0 -0
- package/dist/types/{ui/error-boundary-fallback → common}/generic-error-svg/styled.d.ts +0 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/services/use-plugins/index.d.ts +6 -5
- package/dist/types/services/use-search-query/index.d.ts +3 -0
- package/dist/types/ui/link-picker/index.d.ts +2 -0
- package/dist/types/ui/link-picker/link-search-error/index.d.ts +4 -0
- package/dist/types/ui/link-picker/messages.d.ts +10 -0
- package/dist/types/ui/link-picker/text-input/index.d.ts +0 -1
- package/dist/types/ui/types.d.ts +5 -2
- package/package.json +11 -5
- package/report.api.md +11 -5
|
@@ -29,13 +29,12 @@ var _styled = require("./styled");
|
|
|
29
29
|
|
|
30
30
|
var _ = require("../");
|
|
31
31
|
|
|
32
|
-
var _excluded = ["name", "label", "autoFocus", "
|
|
32
|
+
var _excluded = ["name", "label", "autoFocus", "onRedo", "onUndo", "onChange", "onKeyDown", "onClear", "clearLabel", "error"];
|
|
33
33
|
|
|
34
34
|
var PanelTextInput = function PanelTextInput(props) {
|
|
35
35
|
var name = props.name,
|
|
36
36
|
label = props.label,
|
|
37
37
|
autoFocus = props.autoFocus,
|
|
38
|
-
onSubmit = props.onSubmit,
|
|
39
38
|
onRedo = props.onRedo,
|
|
40
39
|
onUndo = props.onUndo,
|
|
41
40
|
onChange = props.onChange,
|
|
@@ -61,13 +60,7 @@ var PanelTextInput = function PanelTextInput(props) {
|
|
|
61
60
|
onChange(e.currentTarget.value);
|
|
62
61
|
}, [onChange]);
|
|
63
62
|
var handleKeydown = (0, _react.useCallback)(function (e) {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
if (e.keyCode === 13 && onSubmit) {
|
|
67
|
-
e.preventDefault(); // Prevent from submitting if an editor is inside a form.
|
|
68
|
-
|
|
69
|
-
onSubmit(value);
|
|
70
|
-
} else if (typeof onUndo === 'function' && (0, _utils.isUndoEvent)(e)) {
|
|
63
|
+
if (typeof onUndo === 'function' && (0, _utils.isUndoEvent)(e)) {
|
|
71
64
|
e.preventDefault();
|
|
72
65
|
onUndo();
|
|
73
66
|
} else if (typeof onRedo === 'function' && (0, _utils.isRedoEvent)(e)) {
|
|
@@ -78,7 +71,7 @@ var PanelTextInput = function PanelTextInput(props) {
|
|
|
78
71
|
if (onKeyDown) {
|
|
79
72
|
onKeyDown(e);
|
|
80
73
|
}
|
|
81
|
-
}, [
|
|
74
|
+
}, [onUndo, onRedo, onKeyDown]);
|
|
82
75
|
var handleClear = (0, _react.useCallback)(function () {
|
|
83
76
|
if (inputRef.current && onClear) {
|
|
84
77
|
inputRef.current.focus();
|
|
@@ -88,6 +81,7 @@ var PanelTextInput = function PanelTextInput(props) {
|
|
|
88
81
|
var clearText = restProps.value !== '' && (0, _react2.jsx)(_tooltip.default, {
|
|
89
82
|
content: clearLabel
|
|
90
83
|
}, (0, _react2.jsx)("button", {
|
|
84
|
+
type: "button",
|
|
91
85
|
css: _styled.clearTextButtonStyles,
|
|
92
86
|
onClick: handleClear,
|
|
93
87
|
"data-testid": _.testIds.clearUrlButton
|
|
@@ -75,11 +75,6 @@ var linkifyMatch = function linkifyMatch(text) {
|
|
|
75
75
|
|
|
76
76
|
var isSafeUrl = function isSafeUrl(url) {
|
|
77
77
|
var urlTrimmed = url.trim();
|
|
78
|
-
|
|
79
|
-
if (urlTrimmed.length === 0) {
|
|
80
|
-
return true;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
78
|
return whitelistedURLPatterns.some(function (p) {
|
|
84
79
|
return p.test(urlTrimmed);
|
|
85
80
|
});
|
package/dist/cjs/version.json
CHANGED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THIS FILE WAS CREATED VIA CODEGEN DO NOT MODIFY {@see http://go/af-codegen}
|
|
3
|
+
*
|
|
4
|
+
* Generates analytics utilities from the package analytics spec yaml
|
|
5
|
+
*
|
|
6
|
+
* @codegen <<SignedSource::0cc1b4d9c22b31491ded3e581114ab2c>>
|
|
7
|
+
* @codegenCommand yarn workspace @atlaskit/link-picker run codegen-analytics
|
|
8
|
+
*/
|
|
9
|
+
function createEventPayload(eventKey, attributes) {
|
|
10
|
+
const event = eventKey.split('.');
|
|
11
|
+
return {
|
|
12
|
+
eventType: 'ui',
|
|
13
|
+
actionSubject: event[0],
|
|
14
|
+
action: event[1],
|
|
15
|
+
actionSubjectId: event[2],
|
|
16
|
+
attributes: attributes
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export default createEventPayload;
|
|
File without changes
|
|
File without changes
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { useEffect, useRef,
|
|
1
|
+
import { useEffect, useReducer, useMemo, useRef, useState, useCallback } from 'react';
|
|
2
2
|
import { RECENT_SEARCH_LIST_SIZE } from '../../ui/link-picker';
|
|
3
|
-
import { isSafeUrl } from '../../ui/link-picker/url';
|
|
4
3
|
|
|
5
4
|
function reducer(state, payload) {
|
|
6
5
|
return { ...state,
|
|
@@ -8,56 +7,40 @@ function reducer(state, payload) {
|
|
|
8
7
|
};
|
|
9
8
|
}
|
|
10
9
|
|
|
11
|
-
export function usePlugins(state, plugins) {
|
|
10
|
+
export function usePlugins(state, activeTab, plugins) {
|
|
11
|
+
const [retries, setRetries] = useState(0);
|
|
12
12
|
const [pluginState, dispatch] = useReducer(reducer, {
|
|
13
|
-
items:
|
|
13
|
+
items: null,
|
|
14
|
+
error: null,
|
|
14
15
|
isLoading: false
|
|
15
16
|
});
|
|
16
|
-
const {
|
|
17
|
-
url,
|
|
18
|
-
selectedIndex
|
|
19
|
-
} = state;
|
|
20
17
|
const {
|
|
21
18
|
items,
|
|
22
|
-
isLoading
|
|
19
|
+
isLoading,
|
|
20
|
+
error
|
|
23
21
|
} = pluginState;
|
|
24
|
-
const activePlugin = !plugins || plugins.length === 0 ? null : plugins[state.activeTab];
|
|
25
22
|
const queryVersion = useRef(0);
|
|
26
|
-
const
|
|
27
|
-
const selectedItem = items[selectedIndex];
|
|
28
|
-
const isSelectedItem = (selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.url) === url;
|
|
23
|
+
const activePlugin = plugins === null || plugins === void 0 ? void 0 : plugins[activeTab];
|
|
29
24
|
useEffect(() => {
|
|
30
25
|
if (!activePlugin) {
|
|
31
26
|
return;
|
|
32
27
|
}
|
|
33
28
|
|
|
34
|
-
if (
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
if (isSafeUrl(url) && url.length) {
|
|
29
|
+
if (!state) {
|
|
39
30
|
dispatch({
|
|
40
|
-
items:
|
|
41
|
-
isLoading: false
|
|
31
|
+
items: null,
|
|
32
|
+
isLoading: false,
|
|
33
|
+
error: null
|
|
42
34
|
});
|
|
43
35
|
return;
|
|
44
36
|
}
|
|
45
37
|
|
|
46
|
-
const updates = activePlugin.resolve(
|
|
47
|
-
|
|
38
|
+
const updates = activePlugin.resolve(state);
|
|
39
|
+
dispatch({
|
|
40
|
+
items: null,
|
|
41
|
+
isLoading: true,
|
|
42
|
+
error: null
|
|
48
43
|
});
|
|
49
|
-
|
|
50
|
-
if (pluginRef.current !== activePlugin) {
|
|
51
|
-
dispatch({
|
|
52
|
-
items: [],
|
|
53
|
-
isLoading: true
|
|
54
|
-
});
|
|
55
|
-
} else {
|
|
56
|
-
dispatch({
|
|
57
|
-
isLoading: true
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
|
|
61
44
|
const newQuery = ++queryVersion.current;
|
|
62
45
|
|
|
63
46
|
const updateResults = async () => {
|
|
@@ -90,15 +73,17 @@ export function usePlugins(state, plugins) {
|
|
|
90
73
|
return;
|
|
91
74
|
}
|
|
92
75
|
}
|
|
93
|
-
} catch {
|
|
76
|
+
} catch (error) {
|
|
94
77
|
dispatch({
|
|
78
|
+
error,
|
|
79
|
+
items: null,
|
|
95
80
|
isLoading: false
|
|
96
81
|
});
|
|
97
82
|
}
|
|
98
83
|
};
|
|
99
84
|
|
|
100
85
|
updateResults();
|
|
101
|
-
}, [activePlugin, queryVersion,
|
|
86
|
+
}, [activePlugin, queryVersion, state, retries]);
|
|
102
87
|
const tabs = useMemo(() => {
|
|
103
88
|
if (!plugins || plugins.length <= 1) {
|
|
104
89
|
return [];
|
|
@@ -108,12 +93,17 @@ export function usePlugins(state, plugins) {
|
|
|
108
93
|
tabTitle: plugin.tabTitle
|
|
109
94
|
}));
|
|
110
95
|
}, [plugins]);
|
|
96
|
+
const handleRetry = useCallback(() => {
|
|
97
|
+
setRetries(prev => ++prev);
|
|
98
|
+
}, []);
|
|
111
99
|
return {
|
|
112
100
|
tabs,
|
|
113
101
|
items,
|
|
114
102
|
isLoading,
|
|
115
|
-
|
|
116
|
-
|
|
103
|
+
isActivePlugin: !!activePlugin,
|
|
104
|
+
error,
|
|
105
|
+
retry: handleRetry,
|
|
106
|
+
errorFallback: activePlugin === null || activePlugin === void 0 ? void 0 : activePlugin.errorFallback
|
|
117
107
|
};
|
|
118
108
|
}
|
|
119
109
|
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { useRef } from 'react';
|
|
2
|
+
import { isSafeUrl } from '../../ui/link-picker/url';
|
|
3
|
+
export function useSearchQuery(state) {
|
|
4
|
+
var _queryState$current;
|
|
5
|
+
|
|
6
|
+
const queryState = useRef(null);
|
|
7
|
+
/*
|
|
8
|
+
* When state contains a valid url AND is NOT selected from results
|
|
9
|
+
* queryState should be null to clear the items in plugin state
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
if (isSafeUrl(state.url) && state.selectedIndex === -1) {
|
|
13
|
+
queryState.current = null;
|
|
14
|
+
}
|
|
15
|
+
/*
|
|
16
|
+
* When state contains a search term e.g. Not a valid url return a query
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
if (((_queryState$current = queryState.current) === null || _queryState$current === void 0 ? void 0 : _queryState$current.query) !== state.url && !isSafeUrl(state.url)) {
|
|
21
|
+
queryState.current = {
|
|
22
|
+
query: state.url
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/*
|
|
26
|
+
* When state contains a valid url and is selected from the list
|
|
27
|
+
* return current state to prevent triger a new plugin search
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
return queryState.current;
|
|
32
|
+
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { jsx } from '@emotion/react';
|
|
3
3
|
import EmptyState from '@atlaskit/empty-state';
|
|
4
4
|
import { defineMessages, useIntl } from 'react-intl-next';
|
|
5
|
-
import GenericErrorSVG from '
|
|
5
|
+
import GenericErrorSVG from '../../common/generic-error-svg';
|
|
6
6
|
import { rootContainerStyles } from '../link-picker/styled';
|
|
7
7
|
const messages = defineMessages({
|
|
8
8
|
heading: {
|
package/dist/es2019/ui/index.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import React, { memo } from 'react';
|
|
2
2
|
import { AnalyticsErrorBoundary } from '@atlaskit/analytics-next';
|
|
3
3
|
import { LazySuspense, lazyForPaint } from 'react-loosely-lazy';
|
|
4
|
+
import { COMPONENT_NAME, ANALYTICS_CHANNEL } from '../common/constants';
|
|
4
5
|
import { name as packageName, version as packageVersion } from '../version.json';
|
|
5
6
|
import { ErrorBoundaryFallback } from './error-boundary-fallback';
|
|
6
7
|
import { LoaderFallback } from './loader-fallback';
|
|
7
|
-
const COMPONENT_NAME = 'LinkPicker';
|
|
8
|
-
const ANALYTICS_CHANNEL = 'media';
|
|
9
8
|
const PACKAGE_DATA = {
|
|
10
9
|
packageName,
|
|
11
10
|
packageVersion,
|
|
@@ -1,25 +1,31 @@
|
|
|
1
1
|
import _extends from "@babel/runtime/helpers/extends";
|
|
2
2
|
|
|
3
3
|
/** @jsx jsx */
|
|
4
|
-
import { useCallback, useLayoutEffect, useReducer } from 'react';
|
|
4
|
+
import { Fragment, useCallback, useLayoutEffect, useReducer } from 'react';
|
|
5
5
|
import { jsx } from '@emotion/react';
|
|
6
6
|
import { useIntl, FormattedMessage } from 'react-intl-next';
|
|
7
|
+
import { useAnalyticsEvents } from '@atlaskit/analytics-next';
|
|
7
8
|
import Button, { ButtonGroup } from '@atlaskit/button';
|
|
8
9
|
import { FormFooter } from '@atlaskit/form';
|
|
9
10
|
import EditorSearchIcon from '@atlaskit/icon/glyph/editor/search';
|
|
10
11
|
import Tabs, { Tab, TabList } from '@atlaskit/tabs';
|
|
11
12
|
import VisuallyHidden from '@atlaskit/visually-hidden';
|
|
13
|
+
import createEventPayload from '../../analytics.codegen';
|
|
14
|
+
import { ANALYTICS_CHANNEL } from '../../common/constants';
|
|
15
|
+
import { usePlugins } from '../../services/use-plugins';
|
|
16
|
+
import { useSearchQuery } from '../../services/use-search-query';
|
|
12
17
|
import { messages } from './messages';
|
|
13
18
|
import PanelTextInput from './text-input';
|
|
14
19
|
import LinkSearchList from './link-search-list';
|
|
15
20
|
import { normalizeUrl, isSafeUrl } from './url';
|
|
16
21
|
import { rootContainerStyles, searchIconStyles, listTitleStyles, tabsWrapperStyles } from './styled';
|
|
17
22
|
import { browser } from './browser';
|
|
18
|
-
import { transformTimeStamp } from './transformTimeStamp';
|
|
19
23
|
import Announcer from './announcer';
|
|
20
24
|
import LinkSearchNoResults from './link-search-no-results';
|
|
21
|
-
import {
|
|
25
|
+
import { transformTimeStamp } from './transformTimeStamp';
|
|
26
|
+
import LinkSearchError from './link-search-error';
|
|
22
27
|
export const RECENT_SEARCH_LIST_SIZE = 5;
|
|
28
|
+
export const CONTACT_SUPPORT_LINK = 'https://support.atlassian.com/contact/';
|
|
23
29
|
export const testIds = {
|
|
24
30
|
linkPicker: 'link-picker',
|
|
25
31
|
urlInputField: 'link-url',
|
|
@@ -35,7 +41,8 @@ export const testIds = {
|
|
|
35
41
|
searchResultLoadingIndicator: 'link-picker.results-loading-indicator',
|
|
36
42
|
urlError: 'link-error',
|
|
37
43
|
tabList: 'link-picker-tabs',
|
|
38
|
-
tabItem: 'link-picker-tab'
|
|
44
|
+
tabItem: 'link-picker-tab',
|
|
45
|
+
searchError: 'link-search-error'
|
|
39
46
|
};
|
|
40
47
|
const initState = {
|
|
41
48
|
url: '',
|
|
@@ -68,6 +75,11 @@ function LinkPicker({
|
|
|
68
75
|
url: initUrl,
|
|
69
76
|
displayText: initDisplayText
|
|
70
77
|
}) {
|
|
78
|
+
var _queryState$query, _items$length, _errorFallback;
|
|
79
|
+
|
|
80
|
+
const {
|
|
81
|
+
createAnalyticsEvent
|
|
82
|
+
} = useAnalyticsEvents();
|
|
71
83
|
const [state, dispatch] = useReducer(reducer, { ...initState,
|
|
72
84
|
url: normalizeUrl(initUrl) || '',
|
|
73
85
|
displayText: initDisplayText || ''
|
|
@@ -77,17 +89,23 @@ function LinkPicker({
|
|
|
77
89
|
selectedIndex,
|
|
78
90
|
url,
|
|
79
91
|
displayText,
|
|
80
|
-
invalidUrl
|
|
92
|
+
invalidUrl,
|
|
93
|
+
activeTab
|
|
81
94
|
} = state;
|
|
82
|
-
const isEditing = !!initUrl;
|
|
83
95
|
const intl = useIntl();
|
|
96
|
+
const queryState = useSearchQuery(state);
|
|
84
97
|
const {
|
|
85
98
|
items,
|
|
86
99
|
isLoading,
|
|
87
|
-
isSelectedItem,
|
|
88
100
|
isActivePlugin,
|
|
89
|
-
tabs
|
|
90
|
-
|
|
101
|
+
tabs,
|
|
102
|
+
error,
|
|
103
|
+
retry,
|
|
104
|
+
errorFallback
|
|
105
|
+
} = usePlugins(queryState, activeTab, plugins);
|
|
106
|
+
const isEditing = !!initUrl;
|
|
107
|
+
const selectedItem = items === null || items === void 0 ? void 0 : items[selectedIndex];
|
|
108
|
+
const isSelectedItem = (selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.url) === url;
|
|
91
109
|
useLayoutEffect(() => {
|
|
92
110
|
if (onContentResize) {
|
|
93
111
|
onContentResize();
|
|
@@ -145,13 +163,13 @@ function LinkPicker({
|
|
|
145
163
|
});
|
|
146
164
|
}, []);
|
|
147
165
|
const handleMouseEnterResultItem = useCallback(objectId => {
|
|
148
|
-
const index = findIndex(
|
|
166
|
+
const index = items === null || items === void 0 ? void 0 : items.findIndex(item => item.objectId === objectId);
|
|
149
167
|
dispatch({
|
|
150
|
-
activeIndex: index
|
|
168
|
+
activeIndex: index !== null && index !== void 0 ? index : -1
|
|
151
169
|
});
|
|
152
170
|
}, [items]);
|
|
153
171
|
const handleMouseLeaveResultItem = useCallback(objectId => {
|
|
154
|
-
const index = findIndex(
|
|
172
|
+
const index = items === null || items === void 0 ? void 0 : items.findIndex(item => item.objectId === objectId); // This is to avoid updating index that was set by other mouseenter event
|
|
155
173
|
|
|
156
174
|
if (activeIndex === index) {
|
|
157
175
|
dispatch({
|
|
@@ -160,6 +178,8 @@ function LinkPicker({
|
|
|
160
178
|
}
|
|
161
179
|
}, [activeIndex, items]);
|
|
162
180
|
const handleInsert = useCallback((url, title, inputType) => {
|
|
181
|
+
const event = createAnalyticsEvent(createEventPayload('form.submitted.linkPicker', {}));
|
|
182
|
+
event.fire(ANALYTICS_CHANNEL);
|
|
163
183
|
onSubmit({
|
|
164
184
|
url,
|
|
165
185
|
displayText: displayText || null,
|
|
@@ -171,22 +191,23 @@ function LinkPicker({
|
|
|
171
191
|
rawUrl: state.url
|
|
172
192
|
} : {})
|
|
173
193
|
});
|
|
174
|
-
}, [displayText, onSubmit, state.url]);
|
|
194
|
+
}, [displayText, onSubmit, state.url, createAnalyticsEvent]);
|
|
175
195
|
const handleSelected = useCallback(objectId => {
|
|
176
|
-
const selectedItem = items.find(item => item.objectId === objectId);
|
|
196
|
+
const selectedItem = items === null || items === void 0 ? void 0 : items.find(item => item.objectId === objectId);
|
|
177
197
|
|
|
178
198
|
if (selectedItem) {
|
|
179
199
|
const {
|
|
180
200
|
url,
|
|
181
201
|
name
|
|
182
202
|
} = selectedItem;
|
|
203
|
+
dispatchEvent(new Event('submit'));
|
|
183
204
|
handleInsert(url, name, 'typeAhead');
|
|
184
205
|
}
|
|
185
206
|
}, [handleInsert, items]);
|
|
186
|
-
const handleSubmit = useCallback(
|
|
187
|
-
|
|
207
|
+
const handleSubmit = useCallback(event => {
|
|
208
|
+
event.preventDefault();
|
|
188
209
|
|
|
189
|
-
if (isSelectedItem) {
|
|
210
|
+
if (isSelectedItem && selectedItem) {
|
|
190
211
|
return handleInsert(selectedItem.url, selectedItem.name, 'typeAhead');
|
|
191
212
|
}
|
|
192
213
|
|
|
@@ -199,18 +220,18 @@ function LinkPicker({
|
|
|
199
220
|
return dispatch({
|
|
200
221
|
invalidUrl: true
|
|
201
222
|
});
|
|
202
|
-
}, [handleInsert, isSelectedItem,
|
|
223
|
+
}, [handleInsert, isSelectedItem, selectedItem, url]);
|
|
203
224
|
const linkPlaceHolder = isActivePlugin ? messages.placeholder : messages.linkPlaceholder;
|
|
204
|
-
const linkListTitle =
|
|
225
|
+
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;
|
|
205
226
|
const insertButtonMsg = isEditing ? messages.saveButton : messages.insertButton;
|
|
206
|
-
const noResults =
|
|
227
|
+
const noResults = (items === null || items === void 0 ? void 0 : items.length) === 0 && !error;
|
|
207
228
|
const screenReaderDescriptionId = 'search-recent-links-field-description';
|
|
208
229
|
const linkSearchListId = 'link-picker-search-list';
|
|
209
230
|
const ariaActiveDescendant = selectedIndex > -1 ? `link-search-list-item-${selectedIndex}` : ''; // Added workaround with a screen reader Announcer specifically for VoiceOver + Safari
|
|
210
231
|
// as the Aria design pattern for combobox does not work in this case
|
|
211
232
|
// for details: https://a11y-internal.atlassian.net/browse/AK-740
|
|
212
233
|
|
|
213
|
-
const screenReaderText = browser.safari && getScreenReaderText(items, selectedIndex, intl);
|
|
234
|
+
const screenReaderText = browser.safari && getScreenReaderText(items !== null && items !== void 0 ? items : [], selectedIndex, intl);
|
|
214
235
|
const searchIcon = isActivePlugin && jsx("span", {
|
|
215
236
|
css: searchIconStyles,
|
|
216
237
|
"data-testid": testIds.searchIcon
|
|
@@ -218,9 +239,10 @@ function LinkPicker({
|
|
|
218
239
|
size: "medium",
|
|
219
240
|
label: ''
|
|
220
241
|
}));
|
|
221
|
-
return jsx("
|
|
242
|
+
return jsx("form", {
|
|
222
243
|
"data-testid": testIds.linkPicker,
|
|
223
|
-
css: rootContainerStyles
|
|
244
|
+
css: rootContainerStyles,
|
|
245
|
+
onSubmit: handleSubmit
|
|
224
246
|
}, screenReaderText && jsx(Announcer, {
|
|
225
247
|
ariaLive: "assertive",
|
|
226
248
|
text: screenReaderText,
|
|
@@ -246,7 +268,6 @@ function LinkPicker({
|
|
|
246
268
|
"aria-describedby": screenReaderDescriptionId,
|
|
247
269
|
error: invalidUrl ? intl.formatMessage(messages.linkInvalid) : null,
|
|
248
270
|
onClear: handleClear,
|
|
249
|
-
onSubmit: handleSubmit,
|
|
250
271
|
onKeyDown: handleKeyDown,
|
|
251
272
|
onChange: handleChangeUrl
|
|
252
273
|
}), jsx(PanelTextInput, {
|
|
@@ -259,10 +280,9 @@ function LinkPicker({
|
|
|
259
280
|
clearLabel: intl.formatMessage(messages.clearText),
|
|
260
281
|
"aria-label": intl.formatMessage(messages.linkAriaLabel),
|
|
261
282
|
onClear: handleClear,
|
|
262
|
-
onSubmit: handleSubmit,
|
|
263
283
|
onKeyDown: handleKeyDown,
|
|
264
284
|
onChange: handleChangeText
|
|
265
|
-
}), tabs.length > 0 && jsx("div", {
|
|
285
|
+
}), queryState && jsx(Fragment, null, tabs.length > 0 && jsx("div", {
|
|
266
286
|
css: tabsWrapperStyles
|
|
267
287
|
}, jsx(Tabs, {
|
|
268
288
|
id: testIds.tabList,
|
|
@@ -276,7 +296,7 @@ function LinkPicker({
|
|
|
276
296
|
}, jsx(TabList, null, tabs.map(tab => jsx(Tab, {
|
|
277
297
|
key: tab.tabTitle,
|
|
278
298
|
testId: testIds.tabItem
|
|
279
|
-
}, tab.tabTitle))))), !!items.length && jsx("div", {
|
|
299
|
+
}, tab.tabTitle))))), !!(items !== null && items !== void 0 && items.length) && jsx("div", {
|
|
280
300
|
css: listTitleStyles,
|
|
281
301
|
id: testIds.resultListTitle,
|
|
282
302
|
"data-testid": testIds.resultListTitle
|
|
@@ -284,7 +304,7 @@ function LinkPicker({
|
|
|
284
304
|
id: "fabric.smartcard.linkpicker.suggested.results"
|
|
285
305
|
}, url && jsx(FormattedMessage, _extends({}, messages.searchLinkResults, {
|
|
286
306
|
values: {
|
|
287
|
-
count: items.length
|
|
307
|
+
count: (_items$length = items === null || items === void 0 ? void 0 : items.length) !== null && _items$length !== void 0 ? _items$length : 0
|
|
288
308
|
},
|
|
289
309
|
"aria-live": "polite",
|
|
290
310
|
"aria-atomic": "true"
|
|
@@ -293,18 +313,32 @@ function LinkPicker({
|
|
|
293
313
|
ariaControls: "fabric.smartcard.linkpicker.suggested.results",
|
|
294
314
|
id: linkSearchListId,
|
|
295
315
|
role: "listbox",
|
|
296
|
-
items: items,
|
|
316
|
+
items: items !== null && items !== void 0 ? items : [],
|
|
297
317
|
isLoading: isLoading,
|
|
298
318
|
selectedIndex: selectedIndex,
|
|
299
319
|
activeIndex: activeIndex,
|
|
300
320
|
onSelect: handleSelected,
|
|
301
321
|
onMouseEnter: handleMouseEnterResultItem,
|
|
302
322
|
onMouseLeave: handleMouseLeaveResultItem
|
|
303
|
-
}),
|
|
323
|
+
}), error && ((_errorFallback = errorFallback === null || errorFallback === void 0 ? void 0 : errorFallback(error, retry)) !== null && _errorFallback !== void 0 ? _errorFallback : jsx(LinkSearchError, {
|
|
324
|
+
testId: testIds.searchError,
|
|
325
|
+
header: intl.formatMessage(messages.searchErrorHeader),
|
|
326
|
+
description: jsx(FormattedMessage, _extends({}, messages.searchErrorDescription, {
|
|
327
|
+
values: {
|
|
328
|
+
a: label => jsx(Button, {
|
|
329
|
+
appearance: "link",
|
|
330
|
+
spacing: "none",
|
|
331
|
+
href: CONTACT_SUPPORT_LINK,
|
|
332
|
+
target: "_blank",
|
|
333
|
+
rel: "noopener noreferrer"
|
|
334
|
+
}, label)
|
|
335
|
+
}
|
|
336
|
+
}))
|
|
337
|
+
})), noResults && jsx(LinkSearchNoResults, {
|
|
304
338
|
testId: testIds.emptyResultPage,
|
|
305
339
|
header: intl.formatMessage(messages.noResults),
|
|
306
340
|
description: intl.formatMessage(messages.noResultsDescription)
|
|
307
|
-
}), jsx(FormFooter, {
|
|
341
|
+
})), jsx(FormFooter, {
|
|
308
342
|
align: "end"
|
|
309
343
|
}, jsx(ButtonGroup, null, jsx(Button, {
|
|
310
344
|
appearance: "default",
|
|
@@ -313,7 +347,6 @@ function LinkPicker({
|
|
|
313
347
|
}, intl.formatMessage(messages.cancelButton)), jsx(Button, {
|
|
314
348
|
type: "submit",
|
|
315
349
|
appearance: "primary",
|
|
316
|
-
onClick: handleSubmit,
|
|
317
350
|
testId: testIds.insertButton
|
|
318
351
|
}, intl.formatMessage(insertButtonMsg)))));
|
|
319
352
|
}
|
|
@@ -332,17 +365,4 @@ function getScreenReaderText(items, selectedIndex, intl) {
|
|
|
332
365
|
const formattedDate = [date === null || date === void 0 ? void 0 : date.pageAction, date === null || date === void 0 ? void 0 : date.dateString, date === null || date === void 0 ? void 0 : date.timeSince].filter(Boolean).join(' ');
|
|
333
366
|
return [name, container, formattedDate].filter(Boolean).join(', ');
|
|
334
367
|
}
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
function findIndex(array, predicate) {
|
|
338
|
-
let index = -1;
|
|
339
|
-
array.some((item, i) => {
|
|
340
|
-
if (predicate(item)) {
|
|
341
|
-
index = i;
|
|
342
|
-
return true;
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
return false;
|
|
346
|
-
});
|
|
347
|
-
return index;
|
|
348
368
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import _extends from "@babel/runtime/helpers/extends";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import EmptyState from '@atlaskit/empty-state';
|
|
4
|
+
import GenericErrorSVG from '../../../common/generic-error-svg';
|
|
5
|
+
|
|
6
|
+
const LinkSearchError = props => /*#__PURE__*/React.createElement(EmptyState, _extends({}, props, {
|
|
7
|
+
renderImage: () => /*#__PURE__*/React.createElement(GenericErrorSVG, null)
|
|
8
|
+
}));
|
|
9
|
+
|
|
10
|
+
export default LinkSearchError;
|
|
@@ -104,5 +104,15 @@ export const messages = defineMessages({
|
|
|
104
104
|
id: 'fabric.linkPicker.button.save',
|
|
105
105
|
defaultMessage: 'Save',
|
|
106
106
|
description: 'Button to save edited link'
|
|
107
|
+
},
|
|
108
|
+
searchErrorHeader: {
|
|
109
|
+
id: 'fabric.linkPicker.search.error.heading',
|
|
110
|
+
defaultMessage: 'We’re having trouble loading data.',
|
|
111
|
+
description: 'Heading message shown when a search throws an error'
|
|
112
|
+
},
|
|
113
|
+
searchErrorDescription: {
|
|
114
|
+
id: 'fabric.linkPicker.search.error.description',
|
|
115
|
+
defaultMessage: 'Refresh the page, or contact <a>Atlassian Support</a> if this keeps happening.',
|
|
116
|
+
description: 'Describes possible actions when search throws an error'
|
|
107
117
|
}
|
|
108
118
|
});
|
|
@@ -16,7 +16,6 @@ const PanelTextInput = props => {
|
|
|
16
16
|
name,
|
|
17
17
|
label,
|
|
18
18
|
autoFocus,
|
|
19
|
-
onSubmit,
|
|
20
19
|
onRedo,
|
|
21
20
|
onUndo,
|
|
22
21
|
onChange,
|
|
@@ -43,13 +42,7 @@ const PanelTextInput = props => {
|
|
|
43
42
|
onChange(e.currentTarget.value);
|
|
44
43
|
}, [onChange]);
|
|
45
44
|
const handleKeydown = useCallback(e => {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
if (e.keyCode === 13 && onSubmit) {
|
|
49
|
-
e.preventDefault(); // Prevent from submitting if an editor is inside a form.
|
|
50
|
-
|
|
51
|
-
onSubmit(value);
|
|
52
|
-
} else if (typeof onUndo === 'function' && isUndoEvent(e)) {
|
|
45
|
+
if (typeof onUndo === 'function' && isUndoEvent(e)) {
|
|
53
46
|
e.preventDefault();
|
|
54
47
|
onUndo();
|
|
55
48
|
} else if (typeof onRedo === 'function' && isRedoEvent(e)) {
|
|
@@ -60,7 +53,7 @@ const PanelTextInput = props => {
|
|
|
60
53
|
if (onKeyDown) {
|
|
61
54
|
onKeyDown(e);
|
|
62
55
|
}
|
|
63
|
-
}, [
|
|
56
|
+
}, [onUndo, onRedo, onKeyDown]);
|
|
64
57
|
const handleClear = useCallback(() => {
|
|
65
58
|
if (inputRef.current && onClear) {
|
|
66
59
|
inputRef.current.focus();
|
|
@@ -70,6 +63,7 @@ const PanelTextInput = props => {
|
|
|
70
63
|
const clearText = restProps.value !== '' && jsx(Tooltip, {
|
|
71
64
|
content: clearLabel
|
|
72
65
|
}, jsx("button", {
|
|
66
|
+
type: "button",
|
|
73
67
|
css: clearTextButtonStyles,
|
|
74
68
|
onClick: handleClear,
|
|
75
69
|
"data-testid": testIds.clearUrlButton
|
package/dist/es2019/version.json
CHANGED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THIS FILE WAS CREATED VIA CODEGEN DO NOT MODIFY {@see http://go/af-codegen}
|
|
3
|
+
*
|
|
4
|
+
* Generates analytics utilities from the package analytics spec yaml
|
|
5
|
+
*
|
|
6
|
+
* @codegen <<SignedSource::0cc1b4d9c22b31491ded3e581114ab2c>>
|
|
7
|
+
* @codegenCommand yarn workspace @atlaskit/link-picker run codegen-analytics
|
|
8
|
+
*/
|
|
9
|
+
function createEventPayload(eventKey, attributes) {
|
|
10
|
+
var event = eventKey.split('.');
|
|
11
|
+
return {
|
|
12
|
+
eventType: 'ui',
|
|
13
|
+
actionSubject: event[0],
|
|
14
|
+
action: event[1],
|
|
15
|
+
actionSubjectId: event[2],
|
|
16
|
+
attributes: attributes
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export default createEventPayload;
|
|
File without changes
|
|
File without changes
|