@atlaskit/link-picker 1.16.8 → 1.16.10
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 +12 -0
- package/dist/cjs/analytics.codegen.js +3 -4
- package/dist/cjs/common/analytics/context.js +11 -36
- package/dist/cjs/common/analytics/experiences.js +0 -13
- package/dist/cjs/common/analytics/index.js +0 -2
- package/dist/cjs/common/analytics/input-field-tracking.js +16 -35
- package/dist/cjs/common/generic-error-svg/index.js +1 -7
- package/dist/cjs/common/generic-error-svg/styled.js +0 -6
- package/dist/cjs/common/utils/errors.js +0 -15
- package/dist/cjs/controllers/session-provider/index.js +1 -17
- package/dist/cjs/controllers/use-fix-height/index.js +0 -3
- package/dist/cjs/i18n/cs.js +0 -1
- package/dist/cjs/i18n/da.js +0 -1
- package/dist/cjs/i18n/de.js +0 -1
- package/dist/cjs/i18n/en.js +0 -1
- package/dist/cjs/i18n/en_GB.js +0 -1
- package/dist/cjs/i18n/es.js +0 -1
- package/dist/cjs/i18n/fi.js +0 -1
- package/dist/cjs/i18n/fr.js +0 -1
- package/dist/cjs/i18n/hu.js +0 -1
- package/dist/cjs/i18n/it.js +0 -1
- package/dist/cjs/i18n/ja.js +0 -1
- package/dist/cjs/i18n/ko.js +0 -1
- package/dist/cjs/i18n/nb.js +0 -1
- package/dist/cjs/i18n/nl.js +0 -1
- package/dist/cjs/i18n/pl.js +0 -1
- package/dist/cjs/i18n/pt_BR.js +0 -1
- package/dist/cjs/i18n/ru.js +0 -1
- package/dist/cjs/i18n/sv.js +0 -1
- package/dist/cjs/i18n/th.js +0 -1
- package/dist/cjs/i18n/tr.js +0 -1
- package/dist/cjs/i18n/uk.js +0 -1
- package/dist/cjs/i18n/vi.js +0 -1
- package/dist/cjs/i18n/zh.js +0 -1
- package/dist/cjs/i18n/zh_TW.js +0 -1
- package/dist/cjs/index.js +0 -2
- package/dist/cjs/services/use-plugins/index.js +13 -44
- package/dist/cjs/services/use-plugins/reducer.js +0 -13
- package/dist/cjs/services/use-plugins/utils.js +9 -35
- package/dist/cjs/services/use-search-query/index.js +3 -9
- package/dist/cjs/ui/error-boundary/error-boundary-base/index.js +2 -22
- package/dist/cjs/ui/error-boundary/error-boundary-fallback/index.js +1 -9
- package/dist/cjs/ui/error-boundary/index.js +3 -18
- package/dist/cjs/ui/index.js +0 -13
- package/dist/cjs/ui/link-picker/announcer.js +15 -25
- package/dist/cjs/ui/link-picker/browser.js +0 -1
- package/dist/cjs/ui/link-picker/form-footer/index.js +6 -26
- package/dist/cjs/ui/link-picker/form-footer/styled.js +0 -5
- package/dist/cjs/ui/link-picker/form-footer/utils.js +2 -8
- package/dist/cjs/ui/link-picker/index.js +44 -111
- package/dist/cjs/ui/link-picker/link-search-error/index.js +1 -10
- package/dist/cjs/ui/link-picker/link-search-list/index.js +12 -38
- package/dist/cjs/ui/link-picker/link-search-list/link-search-no-results/index.js +1 -9
- package/dist/cjs/ui/link-picker/link-search-list/link-search-no-results/no-results-svg/index.js +1 -5
- package/dist/cjs/ui/link-picker/link-search-list/link-search-no-results/no-results-svg/styled.js +0 -6
- package/dist/cjs/ui/link-picker/link-search-list/link-search-no-results/styled.js +0 -5
- package/dist/cjs/ui/link-picker/link-search-list/styled.js +0 -7
- package/dist/cjs/ui/link-picker/link-search-list/use-track-results-shown/index.js +11 -21
- package/dist/cjs/ui/link-picker/list-item/index.js +11 -32
- package/dist/cjs/ui/link-picker/list-item/styled.js +0 -13
- package/dist/cjs/ui/link-picker/messages.js +0 -2
- package/dist/cjs/ui/link-picker/styled.js +1 -8
- package/dist/cjs/ui/link-picker/text-input/index.js +9 -26
- package/dist/cjs/ui/link-picker/text-input/styled.js +0 -7
- package/dist/cjs/ui/link-picker/track-mount/index.js +1 -11
- package/dist/cjs/ui/link-picker/track-tab-viewed/index.js +2 -10
- package/dist/cjs/ui/link-picker/transformTimeStamp.js +0 -13
- package/dist/cjs/ui/link-picker/utils.js +11 -19
- package/dist/cjs/ui/loader-fallback/index.js +1 -5
- package/dist/cjs/ui/scrolling-tabs/index.js +6 -44
- package/dist/cjs/ui/scrolling-tabs/scrolling-tabs.js +4 -33
- package/dist/cjs/ui/scrolling-tabs/styles.js +0 -3
- package/dist/cjs/version.json +1 -1
- package/dist/es2019/analytics.codegen.js +3 -3
- package/dist/es2019/common/analytics/context.js +11 -13
- package/dist/es2019/common/analytics/experiences.js +0 -1
- package/dist/es2019/common/analytics/input-field-tracking.js +13 -12
- package/dist/es2019/common/generic-error-svg/index.js +0 -4
- package/dist/es2019/common/utils/errors.js +0 -1
- package/dist/es2019/controllers/session-provider/index.js +0 -4
- package/dist/es2019/controllers/use-fix-height/index.js +0 -2
- package/dist/es2019/services/use-plugins/index.js +2 -8
- package/dist/es2019/services/use-plugins/reducer.js +8 -8
- package/dist/es2019/services/use-plugins/utils.js +5 -6
- package/dist/es2019/services/use-search-query/index.js +3 -6
- package/dist/es2019/ui/error-boundary/error-boundary-base/index.js +0 -5
- package/dist/es2019/ui/error-boundary/index.js +2 -4
- package/dist/es2019/ui/index.js +1 -2
- package/dist/es2019/ui/link-picker/announcer.js +6 -1
- package/dist/es2019/ui/link-picker/browser.js +0 -2
- package/dist/es2019/ui/link-picker/form-footer/index.js +0 -5
- package/dist/es2019/ui/link-picker/form-footer/utils.js +2 -5
- package/dist/es2019/ui/link-picker/index.js +21 -37
- package/dist/es2019/ui/link-picker/link-search-error/index.js +0 -3
- package/dist/es2019/ui/link-picker/link-search-list/index.js +2 -6
- package/dist/es2019/ui/link-picker/link-search-list/link-search-no-results/index.js +0 -2
- package/dist/es2019/ui/link-picker/link-search-list/link-search-no-results/no-results-svg/index.js +0 -3
- package/dist/es2019/ui/link-picker/link-search-list/styled.js +2 -2
- package/dist/es2019/ui/link-picker/link-search-list/use-track-results-shown/index.js +7 -5
- package/dist/es2019/ui/link-picker/list-item/index.js +0 -14
- package/dist/es2019/ui/link-picker/list-item/styled.js +2 -4
- package/dist/es2019/ui/link-picker/styled.js +1 -1
- package/dist/es2019/ui/link-picker/text-input/index.js +0 -6
- package/dist/es2019/ui/link-picker/track-mount/index.js +1 -2
- package/dist/es2019/ui/link-picker/track-tab-viewed/index.js +0 -2
- package/dist/es2019/ui/link-picker/transformTimeStamp.js +0 -7
- package/dist/es2019/ui/link-picker/utils.js +7 -5
- package/dist/es2019/ui/scrolling-tabs/index.js +2 -14
- package/dist/es2019/ui/scrolling-tabs/scrolling-tabs.js +0 -14
- package/dist/es2019/version.json +1 -1
- package/dist/esm/analytics.codegen.js +3 -3
- package/dist/esm/common/analytics/context.js +11 -21
- package/dist/esm/common/analytics/experiences.js +0 -3
- package/dist/esm/common/analytics/input-field-tracking.js +16 -22
- package/dist/esm/common/generic-error-svg/index.js +0 -4
- package/dist/esm/common/generic-error-svg/styled.js +0 -2
- package/dist/esm/common/utils/errors.js +0 -8
- package/dist/esm/controllers/session-provider/index.js +1 -7
- package/dist/esm/controllers/use-fix-height/index.js +0 -2
- package/dist/esm/services/use-plugins/index.js +13 -31
- package/dist/esm/services/use-plugins/reducer.js +0 -7
- package/dist/esm/services/use-plugins/utils.js +9 -22
- package/dist/esm/services/use-search-query/index.js +3 -6
- package/dist/esm/ui/error-boundary/error-boundary-base/index.js +2 -13
- package/dist/esm/ui/error-boundary/index.js +3 -5
- package/dist/esm/ui/index.js +1 -2
- package/dist/esm/ui/link-picker/announcer.js +20 -17
- package/dist/esm/ui/link-picker/browser.js +0 -2
- package/dist/esm/ui/link-picker/form-footer/index.js +6 -12
- package/dist/esm/ui/link-picker/form-footer/styled.js +0 -2
- package/dist/esm/ui/link-picker/form-footer/utils.js +2 -5
- package/dist/esm/ui/link-picker/index.js +44 -74
- package/dist/esm/ui/link-picker/link-search-error/index.js +0 -3
- package/dist/esm/ui/link-picker/link-search-list/index.js +12 -20
- package/dist/esm/ui/link-picker/link-search-list/link-search-no-results/index.js +0 -2
- package/dist/esm/ui/link-picker/link-search-list/link-search-no-results/no-results-svg/index.js +0 -3
- package/dist/esm/ui/link-picker/link-search-list/link-search-no-results/no-results-svg/styled.js +0 -2
- package/dist/esm/ui/link-picker/link-search-list/link-search-no-results/styled.js +0 -2
- package/dist/esm/ui/link-picker/link-search-list/styled.js +2 -4
- package/dist/esm/ui/link-picker/link-search-list/use-track-results-shown/index.js +11 -11
- package/dist/esm/ui/link-picker/list-item/index.js +10 -25
- package/dist/esm/ui/link-picker/list-item/styled.js +2 -6
- package/dist/esm/ui/link-picker/styled.js +1 -3
- package/dist/esm/ui/link-picker/text-input/index.js +9 -16
- package/dist/esm/ui/link-picker/text-input/styled.js +0 -2
- package/dist/esm/ui/link-picker/track-mount/index.js +2 -4
- package/dist/esm/ui/link-picker/track-tab-viewed/index.js +1 -5
- package/dist/esm/ui/link-picker/transformTimeStamp.js +0 -7
- package/dist/esm/ui/link-picker/utils.js +11 -9
- package/dist/esm/ui/scrolling-tabs/index.js +6 -28
- package/dist/esm/ui/scrolling-tabs/scrolling-tabs.js +4 -19
- package/dist/esm/version.json +1 -1
- package/dist/types/analytics.codegen.d.ts +2 -2
- package/package.json +8 -13
|
@@ -4,18 +4,16 @@ import { useAnalyticsEvents } from '@atlaskit/analytics-next';
|
|
|
4
4
|
import { ANALYTICS_CHANNEL } from '../constants';
|
|
5
5
|
import createEventPayload from '../../analytics.codegen';
|
|
6
6
|
import { useLinkPickerAnalytics } from '.';
|
|
7
|
-
|
|
8
7
|
const isEventWithInputType = e => {
|
|
9
8
|
return typeof e === 'object' && e !== null && 'inputType' in e;
|
|
10
9
|
};
|
|
11
|
-
|
|
12
10
|
const getChangeEventInputMethodType = event => {
|
|
13
11
|
if (isEventWithInputType(event.nativeEvent) && typeof event.nativeEvent.inputType === 'string' && event.nativeEvent.inputType.includes('insertFromPaste')) {
|
|
14
12
|
return 'paste';
|
|
15
13
|
}
|
|
16
|
-
|
|
17
14
|
return 'manual';
|
|
18
15
|
};
|
|
16
|
+
|
|
19
17
|
/**
|
|
20
18
|
* Wraps an input field and connects it to the link picker analytics context to provide a baseline of analytics tracking
|
|
21
19
|
* @param WrappedComponent The input field to be tracked
|
|
@@ -23,9 +21,8 @@ const getChangeEventInputMethodType = event => {
|
|
|
23
21
|
* @param filterOnChangeEventAttrs Function to hook into and filter/customise the default attribute tracking logic
|
|
24
22
|
* @returns HOC Input field with tracking
|
|
25
23
|
*/
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
export const withInputFieldTracking = (WrappedComponent, field, filterOnChangeEventAttrs = (_, attributes) => attributes // TODO: Consider refactor to use template literal type if it makes these more usable / safe / dev friendly
|
|
24
|
+
export const withInputFieldTracking = (WrappedComponent, field, filterOnChangeEventAttrs = (_, attributes) => attributes
|
|
25
|
+
// TODO: Consider refactor to use template literal type if it makes these more usable / safe / dev friendly
|
|
29
26
|
// contentTypeFn: (value: string) => LinkPickerAnalyticsContextType[`${Field}FieldContent`],
|
|
30
27
|
) => {
|
|
31
28
|
return props => {
|
|
@@ -41,10 +38,12 @@ export const withInputFieldTracking = (WrappedComponent, field, filterOnChangeEv
|
|
|
41
38
|
} = useLinkPickerAnalytics();
|
|
42
39
|
const {
|
|
43
40
|
createAnalyticsEvent
|
|
44
|
-
} = useAnalyticsEvents();
|
|
41
|
+
} = useAnalyticsEvents();
|
|
45
42
|
|
|
46
|
-
|
|
43
|
+
// Ref to track if the value of the field has changed between focus and blur
|
|
44
|
+
const valueOnFocus = useRef(null);
|
|
47
45
|
|
|
46
|
+
// Track the content and input method on every direct change to the input
|
|
48
47
|
const handleOnChange = useCallback(event => {
|
|
49
48
|
// TODO: See above re template literal, improve typesafety here
|
|
50
49
|
// trackAttribute(`${field}FieldContent`, contentTypeFn(event.currentTarget.value));
|
|
@@ -54,22 +53,24 @@ export const withInputFieldTracking = (WrappedComponent, field, filterOnChangeEv
|
|
|
54
53
|
[`${field}FieldContentInputMethod`]: getChangeEventInputMethodType(event)
|
|
55
54
|
}));
|
|
56
55
|
onChange === null || onChange === void 0 ? void 0 : onChange(event);
|
|
57
|
-
}, [onChange, trackAttributes]);
|
|
56
|
+
}, [onChange, trackAttributes]);
|
|
58
57
|
|
|
58
|
+
// Store the value of the field at the time the field is focused so we can know if it changes when the user's focus leaves
|
|
59
59
|
const handleOnFocus = useCallback(event => {
|
|
60
60
|
valueOnFocus.current = event.currentTarget.value;
|
|
61
61
|
onFocus === null || onFocus === void 0 ? void 0 : onFocus(event);
|
|
62
|
-
}, [onFocus]);
|
|
62
|
+
}, [onFocus]);
|
|
63
63
|
|
|
64
|
+
// Fire updated events only when the user's focus leaves the field
|
|
64
65
|
const handleOnBlur = useCallback(event => {
|
|
65
66
|
// Only fire if the value has changed since the field was focused (we are only concerned with the net change to the field)
|
|
66
67
|
if (event.currentTarget.value !== valueOnFocus.current) {
|
|
67
68
|
createAnalyticsEvent(createEventPayload(`ui.textField.updated.${field}Field`, {})).fire(ANALYTICS_CHANNEL);
|
|
68
69
|
}
|
|
69
|
-
|
|
70
70
|
onBlur === null || onBlur === void 0 ? void 0 : onBlur(event);
|
|
71
|
-
}, [onBlur, createAnalyticsEvent]);
|
|
71
|
+
}, [onBlur, createAnalyticsEvent]);
|
|
72
72
|
|
|
73
|
+
// Track the values as null when the text field is cleared
|
|
73
74
|
const handleOnClear = useCallback((...args) => {
|
|
74
75
|
trackAttribute(`${field}FieldContent`, null);
|
|
75
76
|
trackAttribute(`${field}FieldContentInputMethod`, null);
|
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
import _extends from "@babel/runtime/helpers/extends";
|
|
2
|
-
|
|
3
2
|
/* eslint-disable @atlaskit/design-system/ensure-design-token-usage */
|
|
4
|
-
|
|
5
3
|
/** @jsx jsx */
|
|
6
4
|
import { jsx } from '@emotion/react';
|
|
7
5
|
import { genericErrorStyles } from './styled';
|
|
8
|
-
|
|
9
6
|
const GenericErrorSVG = props => {
|
|
10
7
|
const id = 'link-picker-ui-generic-error-svg';
|
|
11
8
|
return jsx("svg", _extends({
|
|
@@ -52,5 +49,4 @@ const GenericErrorSVG = props => {
|
|
|
52
49
|
stopOpacity: ".6"
|
|
53
50
|
}))));
|
|
54
51
|
};
|
|
55
|
-
|
|
56
52
|
export default GenericErrorSVG;
|
|
@@ -3,18 +3,14 @@ import { v4 as uuidv4 } from 'uuid';
|
|
|
3
3
|
import { abortUfoExperience, startUfoExperience, ufoExperience } from '../../common/analytics/experiences';
|
|
4
4
|
export const INIT_CONTEXT = 'SESSION_UNINITIALIZED';
|
|
5
5
|
export const SessionContext = /*#__PURE__*/createContext(INIT_CONTEXT);
|
|
6
|
-
|
|
7
6
|
const useConstructor = callback => {
|
|
8
7
|
const hasBeenFired = useRef(false);
|
|
9
|
-
|
|
10
8
|
if (!hasBeenFired.current) {
|
|
11
9
|
callback();
|
|
12
10
|
hasBeenFired.current = true;
|
|
13
11
|
}
|
|
14
|
-
|
|
15
12
|
return null;
|
|
16
13
|
};
|
|
17
|
-
|
|
18
14
|
export const LinkPickerSessionProvider = ({
|
|
19
15
|
children
|
|
20
16
|
}) => {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { useLayoutEffect, useRef } from 'react';
|
|
2
|
-
|
|
3
2
|
const useFixHeight = shouldFixHeight => {
|
|
4
3
|
const ref = useRef(null);
|
|
5
4
|
const currentHeight = useRef(null);
|
|
@@ -15,5 +14,4 @@ const useFixHeight = shouldFixHeight => {
|
|
|
15
14
|
} : undefined
|
|
16
15
|
};
|
|
17
16
|
};
|
|
18
|
-
|
|
19
17
|
export default useFixHeight;
|
|
@@ -12,8 +12,9 @@ export function usePlugins(state, activeTab, plugins) {
|
|
|
12
12
|
} = useAnalyticsEvents();
|
|
13
13
|
const [retries, setRetries] = useState(0);
|
|
14
14
|
const [pluginState, dispatch] = usePluginReducer();
|
|
15
|
-
const activePlugin = plugins === null || plugins === void 0 ? void 0 : plugins[activeTab];
|
|
15
|
+
const activePlugin = plugins === null || plugins === void 0 ? void 0 : plugins[activeTab];
|
|
16
16
|
|
|
17
|
+
// This useEffect block must be called before any other to ensure onActivation is fired at before resolve
|
|
17
18
|
useEffect(() => {
|
|
18
19
|
if (activePlugin && activePlugin.UNSAFE_onActivation) {
|
|
19
20
|
activePlugin.UNSAFE_onActivation();
|
|
@@ -23,14 +24,12 @@ export function usePlugins(state, activeTab, plugins) {
|
|
|
23
24
|
if (!activePlugin) {
|
|
24
25
|
return;
|
|
25
26
|
}
|
|
26
|
-
|
|
27
27
|
if (!state) {
|
|
28
28
|
dispatch({
|
|
29
29
|
type: 'CLEAR'
|
|
30
30
|
});
|
|
31
31
|
return;
|
|
32
32
|
}
|
|
33
|
-
|
|
34
33
|
dispatch({
|
|
35
34
|
type: 'LOADING'
|
|
36
35
|
});
|
|
@@ -38,11 +37,9 @@ export function usePlugins(state, activeTab, plugins) {
|
|
|
38
37
|
next,
|
|
39
38
|
cancel
|
|
40
39
|
} = resolvePluginUpdates(activePlugin, state);
|
|
41
|
-
|
|
42
40
|
const updateResults = async () => {
|
|
43
41
|
try {
|
|
44
42
|
let isLoading = true;
|
|
45
|
-
|
|
46
43
|
while (isLoading) {
|
|
47
44
|
const {
|
|
48
45
|
value,
|
|
@@ -69,7 +66,6 @@ export function usePlugins(state, activeTab, plugins) {
|
|
|
69
66
|
}
|
|
70
67
|
}
|
|
71
68
|
};
|
|
72
|
-
|
|
73
69
|
updateResults();
|
|
74
70
|
return cancel;
|
|
75
71
|
}, [activePlugin, state, retries, createAnalyticsEvent, dispatch]);
|
|
@@ -77,7 +73,6 @@ export function usePlugins(state, activeTab, plugins) {
|
|
|
77
73
|
if (!plugins || plugins.length <= 1) {
|
|
78
74
|
return [];
|
|
79
75
|
}
|
|
80
|
-
|
|
81
76
|
return plugins.filter(plugin => !!plugin.tabTitle).map(plugin => ({
|
|
82
77
|
tabTitle: plugin.tabTitle
|
|
83
78
|
}));
|
|
@@ -101,7 +96,6 @@ export function usePlugins(state, activeTab, plugins) {
|
|
|
101
96
|
errorFallback: activePlugin === null || activePlugin === void 0 ? void 0 : activePlugin.errorFallback
|
|
102
97
|
};
|
|
103
98
|
}
|
|
104
|
-
|
|
105
99
|
function limit(items) {
|
|
106
100
|
return items.slice(0, RECENT_SEARCH_LIST_SIZE);
|
|
107
101
|
}
|
|
@@ -11,25 +11,25 @@ export const INITIAL_STATE = {
|
|
|
11
11
|
export function reducer(state, action) {
|
|
12
12
|
switch (action.type) {
|
|
13
13
|
case ACTION_CLEAR:
|
|
14
|
-
return {
|
|
14
|
+
return {
|
|
15
|
+
...INITIAL_STATE
|
|
15
16
|
};
|
|
16
|
-
|
|
17
17
|
case ACTION_LOADING:
|
|
18
|
-
return {
|
|
18
|
+
return {
|
|
19
|
+
...INITIAL_STATE,
|
|
19
20
|
isLoading: true
|
|
20
21
|
};
|
|
21
|
-
|
|
22
22
|
case ACTION_SUCCESS:
|
|
23
|
-
return {
|
|
23
|
+
return {
|
|
24
|
+
...state,
|
|
24
25
|
...action.payload,
|
|
25
26
|
error: null
|
|
26
27
|
};
|
|
27
|
-
|
|
28
28
|
case ACTION_ERRORED:
|
|
29
|
-
return {
|
|
29
|
+
return {
|
|
30
|
+
...INITIAL_STATE,
|
|
30
31
|
error: action.payload
|
|
31
32
|
};
|
|
32
|
-
|
|
33
33
|
default:
|
|
34
34
|
return state;
|
|
35
35
|
}
|
|
@@ -11,14 +11,15 @@ export const cancellable = promise => {
|
|
|
11
11
|
}
|
|
12
12
|
};
|
|
13
13
|
};
|
|
14
|
+
|
|
14
15
|
/**
|
|
15
16
|
* Wraps the resolve with a cancellation wrapper and makes promise + generator plugin resolves more compatible
|
|
16
17
|
* Calling cancel for generator plugin prevents it from yielding any further updates
|
|
17
18
|
*/
|
|
18
|
-
|
|
19
19
|
export const resolvePluginUpdates = (plugin, state) => {
|
|
20
|
-
const updates = plugin.resolve(state);
|
|
20
|
+
const updates = plugin.resolve(state);
|
|
21
21
|
|
|
22
|
+
// Promise plugin
|
|
22
23
|
if (updates instanceof Promise) {
|
|
23
24
|
const {
|
|
24
25
|
promise,
|
|
@@ -31,9 +32,9 @@ export const resolvePluginUpdates = (plugin, state) => {
|
|
|
31
32
|
done: true
|
|
32
33
|
})
|
|
33
34
|
};
|
|
34
|
-
}
|
|
35
|
-
|
|
35
|
+
}
|
|
36
36
|
|
|
37
|
+
// Generator plugin
|
|
37
38
|
const cancellationCallbacks = [];
|
|
38
39
|
let cancelled = false;
|
|
39
40
|
return {
|
|
@@ -46,13 +47,11 @@ export const resolvePluginUpdates = (plugin, state) => {
|
|
|
46
47
|
promise,
|
|
47
48
|
cancel
|
|
48
49
|
} = cancellable(updates.next());
|
|
49
|
-
|
|
50
50
|
if (cancelled) {
|
|
51
51
|
cancel();
|
|
52
52
|
} else {
|
|
53
53
|
cancellationCallbacks.push(cancel);
|
|
54
54
|
}
|
|
55
|
-
|
|
56
55
|
return promise;
|
|
57
56
|
}
|
|
58
57
|
};
|
|
@@ -2,33 +2,30 @@ import { useRef } from 'react';
|
|
|
2
2
|
import { isSafeUrl } from '@atlaskit/linking-common/url';
|
|
3
3
|
export function useSearchQuery(state) {
|
|
4
4
|
var _queryState$current;
|
|
5
|
-
|
|
6
5
|
const queryState = useRef(null);
|
|
6
|
+
|
|
7
7
|
/*
|
|
8
8
|
* When state contains a valid url AND is NOT selected from results, and the url was updated
|
|
9
9
|
* from the textbox, queryState should be null to clear the items in plugin state.
|
|
10
10
|
*
|
|
11
11
|
* Checking `lastEditedBy` prevents the items being cleared when the tab is changed.
|
|
12
12
|
*/
|
|
13
|
-
|
|
14
13
|
if (isSafeUrl(state.url) && state.selectedIndex === -1 && !state.preventHidingRecents) {
|
|
15
14
|
queryState.current = null;
|
|
16
15
|
}
|
|
16
|
+
|
|
17
17
|
/*
|
|
18
18
|
* When state contains a search term e.g. Not a valid url return a query
|
|
19
19
|
*/
|
|
20
|
-
|
|
21
|
-
|
|
22
20
|
if (((_queryState$current = queryState.current) === null || _queryState$current === void 0 ? void 0 : _queryState$current.query) !== state.url && !isSafeUrl(state.url)) {
|
|
23
21
|
queryState.current = {
|
|
24
22
|
query: state.url
|
|
25
23
|
};
|
|
26
24
|
}
|
|
25
|
+
|
|
27
26
|
/*
|
|
28
27
|
* When state contains a valid url and is selected from the list
|
|
29
28
|
* return current state to prevent triger a new plugin search
|
|
30
29
|
*/
|
|
31
|
-
|
|
32
|
-
|
|
33
30
|
return queryState.current;
|
|
34
31
|
}
|
|
@@ -7,7 +7,6 @@ export class BaseErrorBoundary extends Component {
|
|
|
7
7
|
hasError: false
|
|
8
8
|
};
|
|
9
9
|
}
|
|
10
|
-
|
|
11
10
|
componentDidCatch(error, info) {
|
|
12
11
|
const {
|
|
13
12
|
onError
|
|
@@ -17,7 +16,6 @@ export class BaseErrorBoundary extends Component {
|
|
|
17
16
|
hasError: true
|
|
18
17
|
});
|
|
19
18
|
}
|
|
20
|
-
|
|
21
19
|
render() {
|
|
22
20
|
const {
|
|
23
21
|
children,
|
|
@@ -26,12 +24,9 @@ export class BaseErrorBoundary extends Component {
|
|
|
26
24
|
const {
|
|
27
25
|
hasError
|
|
28
26
|
} = this.state;
|
|
29
|
-
|
|
30
27
|
if (hasError && ErrorComponent) {
|
|
31
28
|
return /*#__PURE__*/React.createElement(ErrorComponent, null);
|
|
32
29
|
}
|
|
33
|
-
|
|
34
30
|
return children;
|
|
35
31
|
}
|
|
36
|
-
|
|
37
32
|
}
|
|
@@ -6,7 +6,6 @@ import { failUfoExperience, ufoExperience } from '../../common/analytics/experie
|
|
|
6
6
|
import { useLinkPickerSessionId } from '../../controllers/session-provider';
|
|
7
7
|
import { ErrorBoundaryFallback } from './error-boundary-fallback';
|
|
8
8
|
import { BaseErrorBoundary } from './error-boundary-base';
|
|
9
|
-
|
|
10
9
|
function ErrorBoundary({
|
|
11
10
|
children,
|
|
12
11
|
createAnalyticsEvent
|
|
@@ -14,14 +13,14 @@ function ErrorBoundary({
|
|
|
14
13
|
const linkPickerSessionId = useLinkPickerSessionId();
|
|
15
14
|
const handleError = useCallback((error, info) => {
|
|
16
15
|
var _window, _window$navigator, _info$componentStack;
|
|
17
|
-
|
|
18
16
|
// Fire Analytics event
|
|
19
17
|
createAnalyticsEvent(createEventPayload('ui.linkPicker.unhandledErrorCaught', {
|
|
20
18
|
browserInfo: ((_window = window) === null || _window === void 0 ? void 0 : (_window$navigator = _window.navigator) === null || _window$navigator === void 0 ? void 0 : _window$navigator.userAgent) || 'unknown',
|
|
21
19
|
error: error.toString(),
|
|
22
20
|
componentStack: (_info$componentStack = info === null || info === void 0 ? void 0 : info.componentStack) !== null && _info$componentStack !== void 0 ? _info$componentStack : ''
|
|
23
|
-
})).fire(ANALYTICS_CHANNEL);
|
|
21
|
+
})).fire(ANALYTICS_CHANNEL);
|
|
24
22
|
|
|
23
|
+
// Fire UFO failed experience
|
|
25
24
|
failUfoExperience(ufoExperience.mounted, linkPickerSessionId);
|
|
26
25
|
}, [createAnalyticsEvent, linkPickerSessionId]);
|
|
27
26
|
return /*#__PURE__*/React.createElement(BaseErrorBoundary, {
|
|
@@ -29,5 +28,4 @@ function ErrorBoundary({
|
|
|
29
28
|
ErrorComponent: ErrorBoundaryFallback
|
|
30
29
|
}, children);
|
|
31
30
|
}
|
|
32
|
-
|
|
33
31
|
export default withAnalyticsEvents()(ErrorBoundary);
|
package/dist/es2019/ui/index.js
CHANGED
|
@@ -12,8 +12,7 @@ export const PACKAGE_DATA = {
|
|
|
12
12
|
componentName: COMPONENT_NAME,
|
|
13
13
|
source: COMPONENT_NAME
|
|
14
14
|
};
|
|
15
|
-
const LazyLinkPicker = lazyForPaint(() => import(
|
|
16
|
-
/* webpackChunkName: "@atlaskit-internal_link-picker" */
|
|
15
|
+
const LazyLinkPicker = lazyForPaint(() => import( /* webpackChunkName: "@atlaskit-internal_link-picker" */
|
|
17
16
|
'./link-picker'));
|
|
18
17
|
export const ComposedLinkPicker = /*#__PURE__*/memo(props => /*#__PURE__*/React.createElement(AnalyticsContext, {
|
|
19
18
|
data: PACKAGE_DATA
|
|
@@ -1,13 +1,18 @@
|
|
|
1
|
-
import React, { forwardRef, memo, useState, useEffect } from 'react';
|
|
1
|
+
import React, { forwardRef, memo, useState, useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
// How to use:
|
|
2
4
|
// https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Live_Regions#Preferring_specialized_live_region_roles
|
|
3
5
|
// Demo: https://dequeuniversity.com/library/aria/liveregion-playground
|
|
6
|
+
|
|
4
7
|
// Important: Strongly recommend test your solution in all supported screen readers
|
|
5
8
|
// if you use non default value of properties: ariaAtomic, ariaLive, ariaRelevant, role
|
|
9
|
+
|
|
6
10
|
// Note: Text won't be announced if the text message doesn't change after the render.
|
|
7
11
|
// For using a forced announcement in this case, set the 'key' attribute - key={Date.now()}
|
|
8
12
|
|
|
9
13
|
// Note: Flag 'contentRendered' resolves bug with duplicates messages (NVDA + Firefox)
|
|
10
14
|
// https://github.com/nvaccess/nvda/labels/bug%2Fdouble-speaking
|
|
15
|
+
|
|
11
16
|
let timer;
|
|
12
17
|
const Announcer = /*#__PURE__*/forwardRef(({
|
|
13
18
|
ariaAtomic = 'true',
|
|
@@ -12,7 +12,6 @@ const result = {
|
|
|
12
12
|
supportsIntersectionObserver: false,
|
|
13
13
|
supportsResizeObserver: false
|
|
14
14
|
};
|
|
15
|
-
|
|
16
15
|
if (typeof navigator !== 'undefined') {
|
|
17
16
|
const ieEdge = /Edge\/(\d+)/.exec(navigator.userAgent);
|
|
18
17
|
const ieUpTo10 = /MSIE \d/.test(navigator.userAgent);
|
|
@@ -30,5 +29,4 @@ if (typeof navigator !== 'undefined') {
|
|
|
30
29
|
result.supportsIntersectionObserver = typeof window !== 'undefined' && 'IntersectionObserver' in window && 'IntersectionObserverEntry' in window && 'intersectionRatio' in window.IntersectionObserverEntry.prototype;
|
|
31
30
|
result.supportsResizeObserver = typeof window !== 'undefined' && 'ResizeObserver' in window && 'ResizeObserverEntry' in window;
|
|
32
31
|
}
|
|
33
|
-
|
|
34
32
|
export { result as browser };
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import _extends from "@babel/runtime/helpers/extends";
|
|
2
|
-
|
|
3
2
|
/** @jsx jsx */
|
|
4
3
|
import { jsx } from '@emotion/react';
|
|
5
4
|
import { memo } from 'react';
|
|
@@ -29,7 +28,6 @@ export const testIds = {
|
|
|
29
28
|
insertButton: 'link-picker-insert-button',
|
|
30
29
|
cancelButton: 'link-picker-cancel-button'
|
|
31
30
|
};
|
|
32
|
-
|
|
33
31
|
const FormFooter = ({
|
|
34
32
|
isLoading,
|
|
35
33
|
error,
|
|
@@ -40,11 +38,9 @@ const FormFooter = ({
|
|
|
40
38
|
...restProps
|
|
41
39
|
}) => {
|
|
42
40
|
const intl = useIntl();
|
|
43
|
-
|
|
44
41
|
if (error && error instanceof UnauthenticatedError) {
|
|
45
42
|
return null;
|
|
46
43
|
}
|
|
47
|
-
|
|
48
44
|
const isSubmitDisabled = checkSubmitDisabled(isLoading, error, state, items);
|
|
49
45
|
const insertButtonMsg = isEditing ? messages.saveButton : messages.insertButton;
|
|
50
46
|
return jsx("footer", _extends({
|
|
@@ -60,5 +56,4 @@ const FormFooter = ({
|
|
|
60
56
|
isDisabled: isSubmitDisabled
|
|
61
57
|
}, intl.formatMessage(insertButtonMsg))));
|
|
62
58
|
};
|
|
63
|
-
|
|
64
59
|
export default /*#__PURE__*/memo(FormFooter);
|
|
@@ -7,24 +7,21 @@ export const checkSubmitDisabled = (isLoading, error, state, items) => {
|
|
|
7
7
|
if (state && normalizeUrl(state.query)) {
|
|
8
8
|
return false;
|
|
9
9
|
}
|
|
10
|
+
|
|
10
11
|
/*
|
|
11
12
|
* Disable insert button when plugin returns no results,
|
|
12
13
|
* but not if it is a valid url
|
|
13
14
|
*/
|
|
14
|
-
|
|
15
|
-
|
|
16
15
|
if (state && (items === null || items === void 0 ? void 0 : items.length) === 0) {
|
|
17
16
|
return true;
|
|
18
17
|
}
|
|
18
|
+
|
|
19
19
|
/*
|
|
20
20
|
* Disable insert button when is plugin is loading or
|
|
21
21
|
* for any search error
|
|
22
22
|
*/
|
|
23
|
-
|
|
24
|
-
|
|
25
23
|
if (isLoading || error) {
|
|
26
24
|
return true;
|
|
27
25
|
}
|
|
28
|
-
|
|
29
26
|
return false;
|
|
30
27
|
};
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import _extends from "@babel/runtime/helpers/extends";
|
|
2
|
-
|
|
3
2
|
/** @jsx jsx */
|
|
4
3
|
import { Fragment, useCallback, useLayoutEffect, useReducer, memo } from 'react';
|
|
5
4
|
import { jsx } from '@emotion/react';
|
|
@@ -50,38 +49,36 @@ const initState = {
|
|
|
50
49
|
activeTab: 0,
|
|
51
50
|
preventHidingRecents: false
|
|
52
51
|
};
|
|
53
|
-
|
|
54
52
|
function reducer(state, payload) {
|
|
55
53
|
if (payload.url && state.url !== payload.url) {
|
|
56
|
-
return {
|
|
54
|
+
return {
|
|
55
|
+
...state,
|
|
57
56
|
invalidUrl: false,
|
|
58
57
|
selectedIndex: isSafeUrl(payload.url) && payload.url.length ? -1 : state.selectedIndex,
|
|
59
58
|
...payload
|
|
60
59
|
};
|
|
61
60
|
}
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
return {
|
|
62
|
+
...state,
|
|
64
63
|
...payload
|
|
65
64
|
};
|
|
66
65
|
}
|
|
66
|
+
|
|
67
67
|
/**
|
|
68
68
|
* Bind input fields to analytics tracking
|
|
69
69
|
*/
|
|
70
70
|
|
|
71
|
-
|
|
72
71
|
const getLinkFieldContent = value => {
|
|
73
72
|
if (!Boolean(value)) {
|
|
74
73
|
return null;
|
|
75
74
|
}
|
|
76
|
-
|
|
77
75
|
return isSafeUrl(value) ? 'url' : 'text_string';
|
|
78
76
|
};
|
|
79
|
-
|
|
80
|
-
|
|
77
|
+
const LinkInputField = withInputFieldTracking(TextInput, 'link', (event, attributes) => ({
|
|
78
|
+
...attributes,
|
|
81
79
|
linkFieldContent: getLinkFieldContent(event.currentTarget.value)
|
|
82
80
|
}));
|
|
83
81
|
const DisplayTextInputField = withInputFieldTracking(TextInput, 'displayText');
|
|
84
|
-
|
|
85
82
|
function LinkPicker({
|
|
86
83
|
onSubmit,
|
|
87
84
|
onCancel,
|
|
@@ -93,11 +90,11 @@ function LinkPicker({
|
|
|
93
90
|
featureFlags
|
|
94
91
|
}) {
|
|
95
92
|
var _errorFallback;
|
|
96
|
-
|
|
97
93
|
const {
|
|
98
94
|
createAnalyticsEvent
|
|
99
95
|
} = useAnalyticsEvents();
|
|
100
|
-
const [state, dispatch] = useReducer(reducer, {
|
|
96
|
+
const [state, dispatch] = useReducer(reducer, {
|
|
97
|
+
...initState,
|
|
101
98
|
url: normalizeUrl(initUrl) || '',
|
|
102
99
|
displayText: initDisplayText || ''
|
|
103
100
|
});
|
|
@@ -154,29 +151,23 @@ function LinkPicker({
|
|
|
154
151
|
} = event;
|
|
155
152
|
const KEY_ARROW_DOWN = 'ArrowDown';
|
|
156
153
|
const KEY_ARROW_UP = 'ArrowUp';
|
|
157
|
-
|
|
158
154
|
if (!items || !items.length) {
|
|
159
155
|
return;
|
|
160
156
|
}
|
|
161
|
-
|
|
162
157
|
let updatedIndex = activeIndex;
|
|
163
|
-
|
|
164
158
|
switch (key) {
|
|
165
159
|
case KEY_ARROW_DOWN:
|
|
166
160
|
// down
|
|
167
161
|
event.preventDefault();
|
|
168
162
|
updatedIndex = (activeIndex + 1) % items.length;
|
|
169
163
|
break;
|
|
170
|
-
|
|
171
164
|
case KEY_ARROW_UP:
|
|
172
165
|
// up
|
|
173
166
|
event.preventDefault();
|
|
174
167
|
updatedIndex = activeIndex > 0 ? activeIndex - 1 : items.length - 1;
|
|
175
168
|
break;
|
|
176
169
|
}
|
|
177
|
-
|
|
178
170
|
const item = items[updatedIndex];
|
|
179
|
-
|
|
180
171
|
if ([KEY_ARROW_DOWN, KEY_ARROW_UP].includes(key) && item) {
|
|
181
172
|
/**
|
|
182
173
|
* Manually track that the url has been updated using searchResult method
|
|
@@ -208,8 +199,8 @@ function LinkPicker({
|
|
|
208
199
|
});
|
|
209
200
|
}, [dispatch, items]);
|
|
210
201
|
const handleMouseLeaveResultItem = useCallback(objectId => {
|
|
211
|
-
const index = items === null || items === void 0 ? void 0 : items.findIndex(item => item.objectId === objectId);
|
|
212
|
-
|
|
202
|
+
const index = items === null || items === void 0 ? void 0 : items.findIndex(item => item.objectId === objectId);
|
|
203
|
+
// This is to avoid updating index that was set by other mouseenter event
|
|
213
204
|
if (activeIndex === index) {
|
|
214
205
|
dispatch({
|
|
215
206
|
activeIndex: -1
|
|
@@ -217,16 +208,17 @@ function LinkPicker({
|
|
|
217
208
|
}
|
|
218
209
|
}, [dispatch, activeIndex, items]);
|
|
219
210
|
const handleInsert = useCallback((url, title, inputType) => {
|
|
220
|
-
const event = createAnalyticsEvent(createEventPayload('ui.form.submitted.linkPicker', {}));
|
|
221
|
-
// This must happen BEFORE the original event is fired!
|
|
211
|
+
const event = createAnalyticsEvent(createEventPayload('ui.form.submitted.linkPicker', {}));
|
|
222
212
|
|
|
223
|
-
|
|
213
|
+
// Clone the event so that it can be emitted for consumer usage
|
|
214
|
+
// This must happen BEFORE the original event is fired!
|
|
215
|
+
const consumerEvent = event.clone();
|
|
216
|
+
// Cloned event doesnt have the attributes that are added by
|
|
224
217
|
// the analytics listener in the LinkPickerAnalyticsContext, add them here
|
|
225
|
-
|
|
226
218
|
consumerEvent === null || consumerEvent === void 0 ? void 0 : consumerEvent.update({
|
|
227
219
|
attributes: getAttributes()
|
|
228
|
-
});
|
|
229
|
-
|
|
220
|
+
});
|
|
221
|
+
// Dispatch the original event to our channel
|
|
230
222
|
event.fire(ANALYTICS_CHANNEL);
|
|
231
223
|
onSubmit({
|
|
232
224
|
url,
|
|
@@ -242,7 +234,6 @@ function LinkPicker({
|
|
|
242
234
|
}, [displayText, onSubmit, state.url, createAnalyticsEvent, getAttributes]);
|
|
243
235
|
const handleSelected = useCallback(objectId => {
|
|
244
236
|
const selectedItem = items === null || items === void 0 ? void 0 : items.find(item => item.objectId === objectId);
|
|
245
|
-
|
|
246
237
|
if (selectedItem) {
|
|
247
238
|
const {
|
|
248
239
|
url,
|
|
@@ -251,7 +242,6 @@ function LinkPicker({
|
|
|
251
242
|
/**
|
|
252
243
|
* Manually track that the url has been updated using searchResult method
|
|
253
244
|
*/
|
|
254
|
-
|
|
255
245
|
dispatchEvent(new Event('submit'));
|
|
256
246
|
trackAttribute('linkFieldContent', getLinkFieldContent(url));
|
|
257
247
|
trackAttribute('linkFieldContentInputMethod', 'searchResult');
|
|
@@ -261,24 +251,19 @@ function LinkPicker({
|
|
|
261
251
|
}, [handleInsert, trackAttribute, items, activePlugin]);
|
|
262
252
|
const handleSubmit = useCallback(event => {
|
|
263
253
|
event.preventDefault();
|
|
264
|
-
|
|
265
254
|
if (isSelectedItem && selectedItem) {
|
|
266
255
|
return handleInsert(selectedItem.url, selectedItem.name, 'typeAhead');
|
|
267
256
|
}
|
|
268
|
-
|
|
269
257
|
const normalized = normalizeUrl(url);
|
|
270
|
-
|
|
271
258
|
if (normalized) {
|
|
272
259
|
return handleInsert(normalized, null, 'manual');
|
|
273
260
|
}
|
|
274
|
-
|
|
275
261
|
return dispatch({
|
|
276
262
|
invalidUrl: true
|
|
277
263
|
});
|
|
278
264
|
}, [dispatch, handleInsert, isSelectedItem, selectedItem, url]);
|
|
279
265
|
const handleTabChange = useCallback(activeTab => {
|
|
280
266
|
var _plugins$activeTab$ta, _plugins$activeTab;
|
|
281
|
-
|
|
282
267
|
dispatch({
|
|
283
268
|
// We don't want any selection to exist after changing tab, as the selection
|
|
284
269
|
// wouldn't mean anything.
|
|
@@ -294,10 +279,11 @@ function LinkPicker({
|
|
|
294
279
|
const messages = isActivePlugin ? searchMessages : linkMessages;
|
|
295
280
|
const screenReaderDescriptionId = 'search-recent-links-field-description';
|
|
296
281
|
const linkSearchListId = 'link-picker-search-list';
|
|
297
|
-
const ariaActiveDescendant = selectedIndex > -1 ? `link-search-list-item-${selectedIndex}` : '';
|
|
282
|
+
const ariaActiveDescendant = selectedIndex > -1 ? `link-search-list-item-${selectedIndex}` : '';
|
|
283
|
+
|
|
284
|
+
// Added workaround with a screen reader Announcer specifically for VoiceOver + Safari
|
|
298
285
|
// as the Aria design pattern for combobox does not work in this case
|
|
299
286
|
// for details: https://a11y-internal.atlassian.net/browse/AK-740
|
|
300
|
-
|
|
301
287
|
const screenReaderText = browser.safari && getScreenReaderText(items !== null && items !== void 0 ? items : [], selectedIndex, intl);
|
|
302
288
|
const searchIcon = isActivePlugin && jsx("span", {
|
|
303
289
|
css: searchIconStyles,
|
|
@@ -385,7 +371,6 @@ function LinkPicker({
|
|
|
385
371
|
css: !queryState || !(plugins !== null && plugins !== void 0 && plugins.length) ? formFooterMargin : undefined
|
|
386
372
|
}));
|
|
387
373
|
}
|
|
388
|
-
|
|
389
374
|
const DefaultRootComponent = ({
|
|
390
375
|
children
|
|
391
376
|
}) => {
|
|
@@ -393,7 +378,6 @@ const DefaultRootComponent = ({
|
|
|
393
378
|
"data-testid": testIds.linkPickerRoot
|
|
394
379
|
}, children);
|
|
395
380
|
};
|
|
396
|
-
|
|
397
381
|
export default withLinkPickerAnalyticsContext( /*#__PURE__*/memo(({
|
|
398
382
|
component,
|
|
399
383
|
...props
|