UNPKG

@atlaskit/editor-plugin-type-ahead

Version:

Type-ahead plugin for @atlaskit/editor-core

190 lines (185 loc) 8.33 kB
import { TypeAheadAvailableNodes, typeAheadListMessages } from '@atlaskit/editor-common/type-ahead'; import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments'; import { updateSelectedIndex } from './commands/update-selected-index'; import { itemIsDisabled } from './item-is-disabled'; import { pluginKey as typeAheadPluginKey } from './key'; import { StatsModifier } from './stats-modifier'; export var isTypeAheadHandler = function isTypeAheadHandler(handler) { return handler && Object.values(TypeAheadAvailableNodes).includes(handler.id) && typeof handler.trigger === 'string' && typeof handler.selectItem === 'function' && typeof handler.getItems === 'function'; }; /** Is a typeahead plugin open? */ export var isTypeAheadOpen = function isTypeAheadOpen(editorState) { var _typeAheadPluginKey$g; return !!(typeAheadPluginKey !== null && typeAheadPluginKey !== void 0 && (_typeAheadPluginKey$g = typeAheadPluginKey.getState(editorState)) !== null && _typeAheadPluginKey$g !== void 0 && (_typeAheadPluginKey$g = _typeAheadPluginKey$g.decorationSet) !== null && _typeAheadPluginKey$g !== void 0 && _typeAheadPluginKey$g.find().length); }; export var getPluginState = function getPluginState(editorState) { return typeAheadPluginKey.getState(editorState); }; export var getTypeAheadHandler = function getTypeAheadHandler(editorState) { var _typeAheadPluginKey$g2; return (_typeAheadPluginKey$g2 = typeAheadPluginKey.getState(editorState)) === null || _typeAheadPluginKey$g2 === void 0 ? void 0 : _typeAheadPluginKey$g2.triggerHandler; }; export var getTypeAheadQuery = function getTypeAheadQuery(editorState) { var _typeAheadPluginKey$g3; return (_typeAheadPluginKey$g3 = typeAheadPluginKey.getState(editorState)) === null || _typeAheadPluginKey$g3 === void 0 ? void 0 : _typeAheadPluginKey$g3.query; }; export var isTypeAheadAllowed = function isTypeAheadAllowed(state) { var isOpen = isTypeAheadOpen(state); // if the TypeAhead is open // we should not allow it return !isOpen; }; export var findHandler = function findHandler(id, state) { var pluginState = typeAheadPluginKey.getState(state); if (!pluginState || !pluginState.typeAheadHandlers || pluginState.typeAheadHandlers.length === 0) { return null; } var typeAheadHandlers = pluginState.typeAheadHandlers; return typeAheadHandlers.find(function (h) { return h.id === id; }) || null; }; export var skipForwardToSafeItem = function skipForwardToSafeItem(_ref) { var currentIndex = _ref.currentIndex, nextIndex = _ref.nextIndex, listSize = _ref.listSize, itemIsDisabled = _ref.itemIsDisabled; // Use a loop to find the next selectable item for (var idx = nextIndex; idx < listSize; idx++) { if (!itemIsDisabled(idx)) { return idx; } } // We got to the end of the list ^, now try from the start if (editorExperiment('platform_editor_offline_editing_web', true)) { for (var _idx = 0; _idx < nextIndex; _idx++) { if (!itemIsDisabled(_idx)) { return _idx; } } } // If no selectable items are found, return currentIndex return currentIndex; }; export var skipBackwardToSafeItem = function skipBackwardToSafeItem(_ref2) { var currentIndex = _ref2.currentIndex, nextIndex = _ref2.nextIndex, listSize = _ref2.listSize, itemIsDisabled = _ref2.itemIsDisabled; // Use a loop to find the next non-selectable item when going backwards for (var idx = nextIndex; idx >= 0; idx--) { if (!itemIsDisabled(idx)) { return idx; } } // We got to the start of the list ^, now try from the end if (editorExperiment('platform_editor_offline_editing_web', true)) { for (var _idx2 = listSize; _idx2 > nextIndex; _idx2--) { if (!itemIsDisabled(_idx2)) { return _idx2; } } } // If no non-selectable items are found, return currentIndex return currentIndex; }; export var findHandlerByTrigger = function findHandlerByTrigger(_ref3) { var trigger = _ref3.trigger, editorState = _ref3.editorState; var pluginState = typeAheadPluginKey.getState(editorState); if (!pluginState || !pluginState.typeAheadHandlers || pluginState.typeAheadHandlers.length === 0) { return null; } var typeAheadHandlers = pluginState.typeAheadHandlers; return typeAheadHandlers.find(function (h) { return h.trigger === trigger; }) || null; }; export var moveSelectedIndex = function moveSelectedIndex(_ref4) { var editorView = _ref4.editorView, direction = _ref4.direction, api = _ref4.api; return function () { var typeAheadState = getPluginState(editorView.state); if (!typeAheadState) { return; } var selectedIndex = typeAheadState.selectedIndex, items = typeAheadState.items; var stats = typeAheadState.stats instanceof StatsModifier ? typeAheadState.stats : new StatsModifier(); var nextIndex; var isDisabled = function isDisabled(idx) { return itemIsDisabled(items[idx], api); }; if (direction === 'next') { stats.increaseArrowDown(); /** * See: https://product-fabric.atlassian.net/browse/ED-17200 * `selectedIndex` is forced to -1 now to not immediately focus the typeahead * and only do so when there is explicit logic to focus into the typeahead * options. * * This check for "set index to 1 when -1" * - is a temporary workaround to get back the previous behaviour without * entirely reverting the a11y improvements * */ if (selectedIndex === -1 && items.length > 1) { // If the first item is disabled we actually want to skip to the 3rd item // on the first arrow down nextIndex = isDisabled(0) && items.length > 2 ? 2 : 1; } else { nextIndex = selectedIndex >= items.length - 1 ? 0 : selectedIndex + 1; } nextIndex = skipForwardToSafeItem({ currentIndex: selectedIndex, nextIndex: nextIndex, listSize: items.length, itemIsDisabled: isDisabled }); } else { stats.increaseArrowUp(); nextIndex = selectedIndex <= 0 ? items.length - 1 : selectedIndex - 1; nextIndex = skipBackwardToSafeItem({ currentIndex: selectedIndex, nextIndex: nextIndex, listSize: items.length, itemIsDisabled: isDisabled }); } updateSelectedIndex(nextIndex, api)(editorView.state, editorView.dispatch); }; }; export var getTypeAheadListAriaLabels = function getTypeAheadListAriaLabels(trigger, intl, item) { var _item$mention, _item$mention2, _item$emoji, _item$emoji2, _item$emoji3; switch (trigger) { case '@': return { popupAriaLabel: intl.formatMessage(typeAheadListMessages.mentionPopupLabel), listItemAriaLabel: intl.formatMessage(typeAheadListMessages.metionListItemLabel, { name: (item === null || item === void 0 || (_item$mention = item.mention) === null || _item$mention === void 0 ? void 0 : _item$mention.name) || '', shortName: (item === null || item === void 0 || (_item$mention2 = item.mention) === null || _item$mention2 === void 0 ? void 0 : _item$mention2.mentionName) || '' }) }; case '/': return { popupAriaLabel: intl.formatMessage(typeAheadListMessages.quickInsertPopupLabel), listItemAriaLabel: intl.formatMessage(typeAheadListMessages.emojiListItemLabel, { name: (item === null || item === void 0 ? void 0 : item.title) || '', shortcut: (item === null || item === void 0 || (_item$emoji = item.emoji) === null || _item$emoji === void 0 ? void 0 : _item$emoji.shortName) || '' }) }; case ':': return { popupAriaLabel: intl.formatMessage(typeAheadListMessages.emojiPopupLabel), listItemAriaLabel: intl.formatMessage(typeAheadListMessages.emojiListItemLabel, { name: (item === null || item === void 0 || (_item$emoji2 = item.emoji) === null || _item$emoji2 === void 0 ? void 0 : _item$emoji2.name) || '', shortcut: (item === null || item === void 0 || (_item$emoji3 = item.emoji) === null || _item$emoji3 === void 0 ? void 0 : _item$emoji3.shortName) || '' }) }; default: return { popupAriaLabel: intl.formatMessage(typeAheadListMessages.typeAheadPopupLabel) }; } };