UNPKG

@atlaskit/editor-plugin-type-ahead

Version:

Type-ahead plugin for @atlaskit/editor-core

155 lines (154 loc) 6.02 kB
import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'; import { ACTION, INPUT_METHOD } from '@atlaskit/editor-common/analytics'; import { SelectItemMode } from '@atlaskit/editor-common/type-ahead'; import { fg } from '@atlaskit/platform-feature-flags'; import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments'; import { fireTypeAheadClosedAnalyticsEvent } from '../pm-plugins/analytics'; import { updateQuery } from '../pm-plugins/commands/update-query'; import { itemIsDisabled } from '../pm-plugins/item-is-disabled'; import { getPluginState, moveSelectedIndex, skipForwardToSafeItem } from '../pm-plugins/utils'; import { useItemInsert } from './hooks/use-item-insert'; import { useLoadItems } from './hooks/use-load-items'; import { useOnForceSelect } from './hooks/use-on-force-select'; import { InputQuery } from './InputQuery'; export const WrapperTypeAhead = /*#__PURE__*/React.memo(({ triggerHandler, editorView, anchorElement, shouldFocusCursorInsideQuery, popupsMountPoint, popupsBoundariesElement, popupsScrollableElement, inputMethod, getDecorationPosition, reopenQuery, onUndoRedo, api }) => { // @ts-ignore const openElementBrowserModal = triggerHandler === null || triggerHandler === void 0 ? void 0 : triggerHandler.openElementBrowserModal; let showMoreOptionsButton = false; if (editorExperiment('platform_editor_controls', 'variant1')) { showMoreOptionsButton = !!(triggerHandler !== null && triggerHandler !== void 0 && triggerHandler.getMoreOptionsButtonConfig); } const [closed, setClosed] = useState(false); const [query, setQuery] = useState(reopenQuery || ''); const queryRef = useRef(query); const editorViewRef = useRef(editorView); const items = useLoadItems(triggerHandler, editorView, query, showMoreOptionsButton, api); useEffect(() => { if (!closed && fg('platform_editor_ease_of_use_metrics')) { var _api$metrics; api === null || api === void 0 ? void 0 : api.core.actions.execute(api === null || api === void 0 ? void 0 : (_api$metrics = api.metrics) === null || _api$metrics === void 0 ? void 0 : _api$metrics.commands.handleIntentToStartEdit({ shouldStartTimer: false, shouldPersistActiveSession: true })); } }, [closed, api]); useLayoutEffect(() => { queryRef.current = query; }, [query]); const [onItemInsert, onTextInsert] = useItemInsert(triggerHandler, editorView, items, api); const selectNextItem = useMemo(() => moveSelectedIndex({ editorView, direction: 'next', api }), [editorView, api]); const selectPreviousItem = useMemo(() => moveSelectedIndex({ editorView, direction: 'previous', api }), [editorView, api]); const cancel = useCallback(({ setSelectionAt, addPrefixTrigger, text, forceFocusOnEditor }) => { if (editorExperiment('platform_editor_controls', 'variant1')) { var _getPluginState; fireTypeAheadClosedAnalyticsEvent(api, ACTION.CANCELLED, !!queryRef.current, INPUT_METHOD.KEYBOARD, (_getPluginState = getPluginState(editorView.state)) === null || _getPluginState === void 0 ? void 0 : _getPluginState.inputMethod); } setClosed(true); const fullquery = addPrefixTrigger ? `${triggerHandler.trigger}${text}` : text; onTextInsert({ forceFocusOnEditor, setSelectionAt, text: fullquery }); }, [triggerHandler.trigger, onTextInsert, api, editorView.state]); const insertSelectedItem = useCallback((mode = SelectItemMode.SELECTED) => { const { current: view } = editorViewRef; // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const { selectedIndex } = getPluginState(view.state); const safeSelectedIndex = skipForwardToSafeItem({ currentIndex: selectedIndex, nextIndex: 1, listSize: items.length, itemIsDisabled: idx => itemIsDisabled(items[idx], api) }); // If the only safe index is -1 then none are safe - do not insert item if (safeSelectedIndex === -1) { return; } if (editorExperiment('platform_editor_controls', 'variant1')) { var _getPluginState2; fireTypeAheadClosedAnalyticsEvent(api, ACTION.INSERTED, !!queryRef.current, INPUT_METHOD.KEYBOARD, (_getPluginState2 = getPluginState(editorView.state)) === null || _getPluginState2 === void 0 ? void 0 : _getPluginState2.inputMethod); } setClosed(true); queueMicrotask(() => { onItemInsert({ mode, index: selectedIndex, query: queryRef.current }); }); }, [items, api, editorView.state, onItemInsert]); const showTypeAheadPopupList = useCallback(() => {}, []); const closePopup = useCallback(() => { setClosed(true); }, []); useEffect(() => { const { current: view } = editorViewRef; const pluginState = getPluginState(view.state); if (query.length === 0 || query === (pluginState === null || pluginState === void 0 ? void 0 : pluginState.query) || !(pluginState !== null && pluginState !== void 0 && pluginState.triggerHandler)) { return; } updateQuery(query)(view.state, view.dispatch); }, [query, reopenQuery]); useOnForceSelect({ triggerHandler, items, query, editorView, closePopup }); if (closed) { return null; } if (!triggerHandler) { return null; } return /*#__PURE__*/React.createElement(InputQuery, { triggerQueryPrefix: triggerHandler === null || triggerHandler === void 0 ? void 0 : triggerHandler.trigger, onQueryChange: setQuery, onItemSelect: insertSelectedItem, selectNextItem: selectNextItem, selectPreviousItem: selectPreviousItem, onQueryFocus: showTypeAheadPopupList, cancel: cancel, forceFocus: shouldFocusCursorInsideQuery, onUndoRedo: onUndoRedo, reopenQuery: reopenQuery, editorView: editorView, items: items }); }); WrapperTypeAhead.displayName = 'WrapperTypeAhead';