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