@atlaskit/editor-plugin-type-ahead 6.5.11 → 6.5.13

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.
@@ -1,315 +0,0 @@
1
- /* eslint-disable @atlaskit/ui-styling-standard/use-compiled */
2
- /**
3
- * @jsxRuntime classic
4
- * @jsx jsx
5
- */
6
- import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
7
- import { css, jsx } from '@emotion/react';
8
- import rafSchedule from 'raf-schd';
9
- import { useIntl } from 'react-intl-next';
10
-
11
- // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
12
-
13
- import { ACTION, ACTION_SUBJECT, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
14
- import { elementInsertSidePanel } from '@atlaskit/editor-common/messages';
15
- import { findOverflowScrollParent, Popup } from '@atlaskit/editor-common/ui';
16
- import { SideInsertPanel, QuickInsertPanel } from '@atlaskit/editor-element-browser';
17
- import { akEditorFloatingDialogZIndex } from '@atlaskit/editor-shared-styles';
18
- import AddIcon from '@atlaskit/icon/core/add';
19
- import { fg } from '@atlaskit/platform-feature-flags';
20
- import { N0, N50A, N60A } from '@atlaskit/theme/colors';
21
- import { CloseSelectionOptions, TYPE_AHEAD_DECORATION_DATA_ATTRIBUTE, TYPE_AHEAD_POPUP_CONTENT_CLASS } from '../../pm-plugins/constants';
22
- import { TypeAheadErrorFallback } from '../TypeAheadErrorFallback';
23
- const DEFAULT_TYPEAHEAD_MENU_HEIGHT = 520;
24
- // const DEFAULT_TYPEAHEAD_MENU_HEIGHT_NEW = 480;
25
-
26
- const ITEM_PADDING = 12;
27
- const INSERT_PANEL_WIDTH = 320;
28
- const typeAheadContent = css({
29
- background: `var(--ds-surface-overlay, ${N0})`,
30
- borderRadius: "var(--ds-radius-small, 3px)",
31
- boxShadow: `var(--ds-shadow-overlay, ${`0 0 1px ${N60A}, 0 4px 8px -2px ${N50A}`})`,
32
- padding: `${"var(--ds-space-050, 4px)"} 0`,
33
- width: '280px',
34
- maxHeight: '520px' /* ~5.5 visibile items */,
35
- overflowY: 'auto',
36
- MsOverflowStyle: '-ms-autohiding-scrollbar',
37
- position: 'relative'
38
- });
39
- // const typeAheadContentOverride = css({
40
- // maxHeight: `${DEFAULT_TYPEAHEAD_MENU_HEIGHT_NEW}px`,
41
- // });
42
-
43
- const OFFSET = [0, 8];
44
- export const TypeAheadPopup = /*#__PURE__*/React.memo(props => {
45
- const {
46
- triggerHandler,
47
- anchorElement,
48
- popupsMountPoint,
49
- popupsBoundariesElement,
50
- popupsScrollableElement,
51
- items,
52
- errorInfo,
53
- onItemInsert,
54
- isEmptyQuery,
55
- cancel,
56
- api,
57
- query,
58
- setSelectedItem
59
- } = props;
60
- const ref = useRef(null);
61
- const {
62
- formatMessage
63
- } = useIntl();
64
- const defaultMenuHeight = DEFAULT_TYPEAHEAD_MENU_HEIGHT;
65
- const startTime = useMemo(() => performance.now(),
66
- // In case those props changes
67
- // we need to recreate the startTime
68
- [items, isEmptyQuery, triggerHandler] // eslint-disable-line react-hooks/exhaustive-deps
69
- );
70
- useEffect(() => {
71
- var _api$analytics, _api$analytics$action, _api$analytics2, _api$analytics2$actio;
72
- if (!(api !== null && api !== void 0 && (_api$analytics = api.analytics) !== null && _api$analytics !== void 0 && (_api$analytics$action = _api$analytics.actions) !== null && _api$analytics$action !== void 0 && _api$analytics$action.fireAnalyticsEvent)) {
73
- return;
74
- }
75
- const stopTime = performance.now();
76
- const time = stopTime - startTime;
77
- api === null || api === void 0 ? void 0 : (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 ? void 0 : (_api$analytics2$actio = _api$analytics2.actions) === null || _api$analytics2$actio === void 0 ? void 0 : _api$analytics2$actio.fireAnalyticsEvent({
78
- action: ACTION.RENDERED,
79
- actionSubject: ACTION_SUBJECT.TYPEAHEAD,
80
- eventType: EVENT_TYPE.OPERATIONAL,
81
- attributes: {
82
- time,
83
- items: items.length,
84
- initial: isEmptyQuery
85
- }
86
- });
87
- }, [startTime, items, isEmptyQuery,
88
- // In case the current triggerHandler changes
89
- // e.g: Inserting a mention using the quick insert
90
- // we need to send the event again
91
- // eslint-disable-next-line react-hooks/exhaustive-deps
92
- triggerHandler, api]);
93
-
94
- // useEffect(() => {
95
- // if (!api?.analytics?.actions?.fireAnalyticsEvent) {
96
- // return;
97
- // }
98
-
99
- // api?.analytics?.actions?.fireAnalyticsEvent({
100
- // action: ACTION.VIEWED,
101
- // actionSubject: ACTION_SUBJECT.TYPEAHEAD_ITEM,
102
- // eventType: EVENT_TYPE.OPERATIONAL,
103
- // attributes: {
104
- // index: selectedIndex,
105
- // items: items.length,
106
- // },
107
- // });
108
- // }, [
109
- // items,
110
- // api,
111
- // selectedIndex,
112
- // // In case the current triggerHandler changes
113
- // // e.g: Inserting a mention using the quick insert
114
- // // we need to send the event again
115
- // // eslint-disable-next-line react-hooks/exhaustive-deps
116
- // triggerHandler,
117
- // ]);
118
-
119
- const [fitHeight, setFitHeight] = useState(defaultMenuHeight);
120
- const getFitHeight = useCallback(() => {
121
- if (!anchorElement || !popupsMountPoint) {
122
- return;
123
- }
124
- const target = anchorElement;
125
- const {
126
- top: targetTop,
127
- height: targetHeight
128
- } = target.getBoundingClientRect();
129
- const boundariesElement = popupsBoundariesElement || document.body;
130
- const {
131
- height: boundariesHeight,
132
- top: boundariesTop
133
- } = boundariesElement.getBoundingClientRect();
134
-
135
- // Calculating the space above and space below our decoration
136
- const spaceAbove = targetTop - (boundariesTop - boundariesElement.scrollTop);
137
- const spaceBelow = boundariesTop + boundariesHeight - (targetTop + targetHeight);
138
-
139
- // Keep default height if more than enough space
140
- if (spaceBelow >= defaultMenuHeight) {
141
- return setFitHeight(defaultMenuHeight);
142
- }
143
-
144
- // Determines whether typeahead will fit above or below decoration
145
- // and return the space available.
146
- const newFitHeight = spaceBelow >= spaceAbove ? spaceBelow : spaceAbove;
147
-
148
- // Each typeahead item has some padding
149
- // We want to leave some space at the top so first item
150
- // is not partially cropped
151
- const fitHeightWithSpace = newFitHeight - ITEM_PADDING * 2;
152
-
153
- // Ensure typeahead height is max its default height
154
- const minFitHeight = Math.min(defaultMenuHeight, fitHeightWithSpace);
155
- return setFitHeight(minFitHeight);
156
- }, [anchorElement, defaultMenuHeight, popupsBoundariesElement, popupsMountPoint]);
157
- const getFitHeightDebounced = rafSchedule(getFitHeight);
158
- useLayoutEffect(() => {
159
- // Ignored via go/ees005
160
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
161
- const scrollableElement = popupsScrollableElement || findOverflowScrollParent(anchorElement);
162
- getFitHeight();
163
- // Ignored via go/ees005
164
- // eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
165
- window.addEventListener('resize', getFitHeightDebounced);
166
- if (scrollableElement) {
167
- // Ignored via go/ees005
168
- // eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
169
- scrollableElement.addEventListener('scroll', getFitHeightDebounced);
170
- }
171
- return () => {
172
- // Ignored via go/ees005
173
- // eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
174
- window.removeEventListener('resize', getFitHeightDebounced);
175
- if (scrollableElement) {
176
- // Ignored via go/ees005
177
- // eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
178
- scrollableElement.removeEventListener('scroll', getFitHeightDebounced);
179
- }
180
- };
181
- }, [anchorElement, popupsScrollableElement, getFitHeightDebounced, getFitHeight]);
182
- useLayoutEffect(() => {
183
- const focusOut = event => {
184
- var _window$getSelection;
185
- const {
186
- relatedTarget
187
- } = event;
188
-
189
- // Given the user is changing the focus
190
- // When the target is inside the TypeAhead Popup
191
- // Then the popup should stay open
192
- if (relatedTarget instanceof HTMLElement && relatedTarget.closest && (relatedTarget.closest(`.${TYPE_AHEAD_POPUP_CONTENT_CLASS}`) || relatedTarget.closest(`[data-type-ahead="${TYPE_AHEAD_DECORATION_DATA_ATTRIBUTE}"]`))) {
193
- return;
194
- }
195
-
196
- // Handles cases like emoji and @ typeaheads that open new typeaheads
197
- const isTextSelected = ((_window$getSelection = window.getSelection()) === null || _window$getSelection === void 0 ? void 0 : _window$getSelection.type) === 'Range';
198
- const innerEditor = anchorElement.closest('.extension-editable-area');
199
- if (innerEditor) {
200
- // When there is no related target, we default to not closing the popup
201
- let newFocusInsideCurrentEditor = !relatedTarget;
202
- if (relatedTarget instanceof HTMLElement) {
203
- // check if the new focus is inside inner editor, keep popup opens
204
- newFocusInsideCurrentEditor = innerEditor.contains(relatedTarget);
205
- }
206
- if (!isTextSelected && newFocusInsideCurrentEditor) {
207
- return;
208
- }
209
- } else {
210
- // if the current focus in outer editor, keep the existing behaviour, do not close the pop up if text is not selected
211
- if (!isTextSelected) {
212
- return;
213
- }
214
- }
215
- cancel({
216
- addPrefixTrigger: true,
217
- setSelectionAt: CloseSelectionOptions.AFTER_TEXT_INSERTED,
218
- forceFocusOnEditor: false
219
- });
220
- };
221
- const {
222
- current: element
223
- } = ref;
224
- // Ignored via go/ees005
225
- // eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
226
- element === null || element === void 0 ? void 0 : element.addEventListener('focusout', focusOut);
227
- return () => {
228
- // Ignored via go/ees005
229
- // eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
230
- element === null || element === void 0 ? void 0 : element.removeEventListener('focusout', focusOut);
231
- };
232
- }, [ref, cancel, anchorElement]);
233
-
234
- // TODO: ED-17443 - When you press escape on typeahead panel, it should remove focus and close the panel
235
- // This is the expected keyboard behaviour advised by the Accessibility team
236
- useLayoutEffect(() => {
237
- const escape = event => {
238
- if (event.key === 'Escape') {
239
- cancel({
240
- addPrefixTrigger: true,
241
- setSelectionAt: CloseSelectionOptions.AFTER_TEXT_INSERTED,
242
- forceFocusOnEditor: true
243
- });
244
- }
245
- };
246
- const {
247
- current: element
248
- } = ref;
249
- // Ignored via go/ees005
250
- // eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
251
- element === null || element === void 0 ? void 0 : element.addEventListener('keydown', escape);
252
- return () => {
253
- // Ignored via go/ees005
254
- // eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
255
- element === null || element === void 0 ? void 0 : element.removeEventListener('keydown', escape);
256
- };
257
- }, [ref, cancel]);
258
- const handleViewAllItemsClick = useCallback(() => {
259
- var _api$contextPanel, _api$contextPanel$act;
260
- const showContextPanel = api === null || api === void 0 ? void 0 : (_api$contextPanel = api.contextPanel) === null || _api$contextPanel === void 0 ? void 0 : (_api$contextPanel$act = _api$contextPanel.actions) === null || _api$contextPanel$act === void 0 ? void 0 : _api$contextPanel$act.showPanel;
261
- if (!showContextPanel || !items) {
262
- return;
263
- }
264
-
265
- // Opens main editor controls side panel
266
- showContextPanel({
267
- id: 'editor-element-insert-sidebar-panel',
268
- headerComponentElements: {
269
- headerLabel: elementInsertSidePanel.title,
270
- HeaderIcon: () => jsx(AddIcon, {
271
- label: formatMessage(elementInsertSidePanel.title)
272
- })
273
- },
274
- BodyComponent: () => {
275
- return jsx(SideInsertPanel, {
276
- items: items,
277
- onItemInsert: onItemInsert
278
- });
279
- }
280
- }, 'push', INSERT_PANEL_WIDTH);
281
-
282
- // Closes typeahead
283
- cancel({
284
- addPrefixTrigger: true,
285
- setSelectionAt: CloseSelectionOptions.AFTER_TEXT_INSERTED,
286
- forceFocusOnEditor: true
287
- });
288
- }, [api, cancel, formatMessage, items, onItemInsert]);
289
- return jsx(Popup, {
290
- zIndex: akEditorFloatingDialogZIndex,
291
- target: anchorElement,
292
- mountTo: popupsMountPoint,
293
- boundariesElement: popupsBoundariesElement,
294
- scrollableElement: popupsScrollableElement,
295
- fitHeight: fitHeight,
296
- fitWidth: 280,
297
- offset: OFFSET,
298
- ariaLabel: null,
299
- preventOverflow: true
300
- }, jsx("div", {
301
- css: [typeAheadContent],
302
- tabIndex: fg('platform_editor_a11y_fix_typeahead_tabindex') ? undefined : 0
303
- // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
304
- ,
305
- className: TYPE_AHEAD_POPUP_CONTENT_CLASS,
306
- ref: ref
307
- }, errorInfo ? jsx(TypeAheadErrorFallback, null) : jsx(React.Fragment, null, jsx(QuickInsertPanel, {
308
- items: items,
309
- onItemInsert: onItemInsert,
310
- query: query,
311
- setSelectedItem: setSelectedItem,
312
- onViewAllItemsClick: Boolean(api === null || api === void 0 ? void 0 : api.contextPanel) ? handleViewAllItemsClick : undefined
313
- }))));
314
- });
315
- TypeAheadPopup.displayName = 'TypeAheadPopup';
@@ -1,77 +0,0 @@
1
- import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
2
- import React from 'react';
3
- import { SelectItemMode } from '@atlaskit/editor-common/type-ahead';
4
- import { updateSelectedIndex } from '../../pm-plugins/commands/update-selected-index';
5
- import { useItemInsert } from '../hooks/use-item-insert';
6
- import { TypeAheadPopup as TypeAheadPopupModern } from './TypeAheadPopup';
7
- export var TypeAheadMenu = /*#__PURE__*/React.memo(function (_ref) {
8
- var _popupMountRef$curren, _popupMountRef$curren2, _popupMountRef$curren3;
9
- var editorView = _ref.editorView,
10
- popupMountRef = _ref.popupMountRef,
11
- typeAheadState = _ref.typeAheadState,
12
- api = _ref.api;
13
- var isOpen = typeAheadState.decorationSet.find().length > 0;
14
- var triggerHandler = typeAheadState.triggerHandler,
15
- items = typeAheadState.items,
16
- errorInfo = typeAheadState.errorInfo,
17
- decorationElement = typeAheadState.decorationElement,
18
- decorationSet = typeAheadState.decorationSet,
19
- query = typeAheadState.query;
20
- var _useItemInsert = useItemInsert(
21
- // Ignored via go/ees005
22
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
23
- triggerHandler, editorView, items, api),
24
- _useItemInsert2 = _slicedToArray(_useItemInsert, 2),
25
- onItemInsert = _useItemInsert2[0],
26
- onTextInsert = _useItemInsert2[1];
27
- var setSelectedItem = React.useCallback(function (_ref2) {
28
- var nextIndex = _ref2.index;
29
- queueMicrotask(function () {
30
- updateSelectedIndex(nextIndex, api)(editorView.state, editorView.dispatch);
31
- });
32
- }, [editorView, api]);
33
- var insertItem = React.useCallback(function () {
34
- var mode = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : SelectItemMode.SELECTED;
35
- var index = arguments.length > 1 ? arguments[1] : undefined;
36
- queueMicrotask(function () {
37
- onItemInsert({
38
- mode: mode,
39
- index: index,
40
- query: query
41
- });
42
- });
43
- }, [onItemInsert, query]);
44
- var cancel = React.useCallback(function (_ref3) {
45
- var setSelectionAt = _ref3.setSelectionAt,
46
- addPrefixTrigger = _ref3.addPrefixTrigger,
47
- forceFocusOnEditor = _ref3.forceFocusOnEditor;
48
- var fullQuery = addPrefixTrigger ? "".concat(triggerHandler === null || triggerHandler === void 0 ? void 0 : triggerHandler.trigger).concat(query) : query;
49
- onTextInsert({
50
- forceFocusOnEditor: forceFocusOnEditor,
51
- setSelectionAt: setSelectionAt,
52
- text: fullQuery
53
- });
54
- }, [triggerHandler, onTextInsert, query]);
55
- if (!isOpen || !triggerHandler || !(decorationElement instanceof HTMLElement) || items.length === 0 && !errorInfo) {
56
- return null;
57
- }
58
- return /*#__PURE__*/React.createElement(TypeAheadPopupModern, {
59
- editorView: editorView,
60
- popupsMountPoint: (_popupMountRef$curren = popupMountRef.current) === null || _popupMountRef$curren === void 0 ? void 0 : _popupMountRef$curren.popupsMountPoint,
61
- popupsBoundariesElement: (_popupMountRef$curren2 = popupMountRef.current) === null || _popupMountRef$curren2 === void 0 ? void 0 : _popupMountRef$curren2.popupsBoundariesElement,
62
- popupsScrollableElement: (_popupMountRef$curren3 = popupMountRef.current) === null || _popupMountRef$curren3 === void 0 ? void 0 : _popupMountRef$curren3.popupsScrollableElement,
63
- anchorElement: decorationElement,
64
- triggerHandler: triggerHandler,
65
- items: items,
66
- errorInfo: errorInfo
67
- // selectedIndex={selectedIndex}
68
- ,
69
- setSelectedItem: setSelectedItem,
70
- onItemInsert: insertItem,
71
- decorationSet: decorationSet,
72
- isEmptyQuery: !query,
73
- query: query,
74
- cancel: cancel,
75
- api: api
76
- });
77
- });