@atlaskit/editor-plugin-quick-insert
Version:
Quick insert plugin for @atlaskit/editor-core
155 lines (154 loc) • 7.57 kB
JavaScript
import { createQuickInsertMatcher } from '@atlaskit/editor-common/quick-insert/create-quick-insert-matcher';
import { ASK_ROVO_MENU_ITEM } from '@atlaskit/editor-common/quick-insert/keys';
import { normalizeQuickInsertMatchResult } from '../normalizeQuickInsertMatchResult';
const compareRanks = (left, right) => {
for (let index = 0; index < Math.max(left.length, right.length); index++) {
var _left$index, _right$index;
const difference = ((_left$index = left[index]) !== null && _left$index !== void 0 ? _left$index : 0) - ((_right$index = right[index]) !== null && _right$index !== void 0 ? _right$index : 0);
if (difference !== 0) {
return difference;
}
}
return 0;
};
const getChildren = (components, parentKey, surfaceContext) => components.filter(component => {
var _component$parents, _component$isHidden;
return ((_component$parents = component.parents) === null || _component$parents === void 0 ? void 0 : _component$parents.some(parent => parent.key === parentKey)) && ((_component$isHidden = component.isHidden) === null || _component$isHidden === void 0 ? void 0 : _component$isHidden.call(component, {
surfaceContext
})) !== true;
});
const getParentRank = (registration, parentKey) => {
var _registration$parents, _registration$parents2, _registration$parents3;
return (_registration$parents = (_registration$parents2 = registration.parents) === null || _registration$parents2 === void 0 ? void 0 : (_registration$parents3 = _registration$parents2.find(parent => parent.key === parentKey)) === null || _registration$parents3 === void 0 ? void 0 : _registration$parents3.rank) !== null && _registration$parents !== void 0 ? _registration$parents : Number.MAX_SAFE_INTEGER;
};
const getDescendantItems = (components, parentKey, ancestorRanks, sectionKey, surfaceContext) => getChildren(components, parentKey, surfaceContext).flatMap(component => {
const ranks = [...ancestorRanks, getParentRank(component, parentKey)];
if (component.type === 'menu-item') {
return component.component ? [{
ranks,
registration: component,
sectionKeys: [sectionKey]
}] : [];
}
return getDescendantItems(components, component.key, ranks, sectionKey, surfaceContext);
});
/**
* Builds the Element Browser's view of the resolved Quick Insert registry.
* The caller provides only components rooted at the Quick Insert menu surface.
*/
export const createRegistryElementBrowserModel = (components, {
footerKey,
overflowKeys,
recommendedRegistrations = [],
recommendedSectionKey,
rootKey,
surfaceContext
}) => {
const excludedKeys = new Set([footerKey, recommendedSectionKey, ...overflowKeys]);
const visibleComponents = components.filter(component => !excludedKeys.has(component.key));
const sections = getChildren(visibleComponents, rootKey, surfaceContext).filter(component => component.type === 'menu-section').map(section => ({
key: section.key,
rank: getParentRank(section, rootKey)
})).sort((left, right) => left.rank - right.rank);
const itemByKey = new Map();
sections.forEach(section => {
getDescendantItems(visibleComponents, section.key, [section.rank], section.key, surfaceContext).forEach(item => {
const existing = itemByKey.get(item.registration.key);
if (!existing) {
itemByKey.set(item.registration.key, item);
return;
}
const sectionKeys = [...new Set([...existing.sectionKeys, ...item.sectionKeys])];
itemByKey.set(item.registration.key, compareRanks(item.ranks, existing.ranks) < 0 ? {
...item,
sectionKeys
} : {
...existing,
sectionKeys
});
});
});
const items = [...itemByKey.values()].sort((left, right) => compareRanks(left.ranks, right.ranks));
const fallbackItems = items.filter(({
registration
}) => registration.key === ASK_ROVO_MENU_ITEM.key);
const recommendedItems = [...new Set(recommendedRegistrations.map(({
key
}) => key))].flatMap(key => {
var _itemByKey$get;
return (_itemByKey$get = itemByKey.get(key)) !== null && _itemByKey$get !== void 0 ? _itemByKey$get : [];
});
return {
fallbackItems: fallbackItems.length > 0 ? fallbackItems : undefined,
items,
recommendedItems,
sections
};
};
/**
* Lays out Recommended so every row is full: wide tiles take half a row and regular tiles a third.
* An odd count of three or more ends with a row of three regular tiles; every other tile is wide.
*/
export const getRecommendedTileSize = (index, count) => count >= 3 && count % 2 === 1 && index >= count - 3 ? 'regular' : 'wide';
export const getInitialRegistryElementBrowserSection = (model, requestedSection) => model.sections.some(section => section.key === requestedSection) ? requestedSection : undefined;
export const getRegistryElementBrowserItems = ({
formatMessage,
model,
query,
section
}) => {
const withDescription = item => {
var _createQuickInsertMat;
return {
...item,
description: (_createQuickInsertMat = createQuickInsertMatcher.getDescription) === null || _createQuickInsertMat === void 0 ? void 0 : _createQuickInsertMat.call(createQuickInsertMatcher, item.registration.match, formatMessage)
};
};
if (section === undefined && query === '') {
const recommendedKeys = new Set(model.recommendedItems.map(({
registration
}) => registration.key));
return {
items: model.items.filter(({
registration
}) => !recommendedKeys.has(registration.key)).map(withDescription),
recommendedItems: model.recommendedItems.map(withDescription)
};
}
const normalizedQuery = query.trim();
const itemsWithDescriptions = (section ? model.items.filter(item => item.sectionKeys.includes(section)) : model.items).map(withDescription);
if (!normalizedQuery) {
return {
items: itemsWithDescriptions,
recommendedItems: []
};
}
const matches = itemsWithDescriptions.flatMap(item => {
var _item$registration$ma, _item$registration;
const result = (_item$registration$ma = (_item$registration = item.registration).match) === null || _item$registration$ma === void 0 ? void 0 : _item$registration$ma.call(_item$registration, {
formatMessage,
itemKey: item.registration.key,
query: normalizedQuery
});
return result ? [{
...item,
...normalizeQuickInsertMatchResult(result)
}] : [];
});
const prioritized = matches.filter(({
priorityGroup
}) => priorityGroup !== undefined);
const unprioritized = matches.filter(({
priorityGroup
}) => priorityGroup === undefined);
return {
items: [...prioritized.sort((left, right) => {
var _right$priorityGroup, _left$priorityGroup;
return ((_right$priorityGroup = right.priorityGroup) !== null && _right$priorityGroup !== void 0 ? _right$priorityGroup : 0) - ((_left$priorityGroup = left.priorityGroup) !== null && _left$priorityGroup !== void 0 ? _left$priorityGroup : 0) || left.score - right.score || compareRanks(left.ranks, right.ranks) || left.registration.key.localeCompare(right.registration.key);
}), ...unprioritized.sort((left, right) => {
var _left$ranks$, _right$ranks$;
return ((_left$ranks$ = left.ranks[0]) !== null && _left$ranks$ !== void 0 ? _left$ranks$ : 0) - ((_right$ranks$ = right.ranks[0]) !== null && _right$ranks$ !== void 0 ? _right$ranks$ : 0) || left.score - right.score || compareRanks(left.ranks, right.ranks) || left.registration.key.localeCompare(right.registration.key);
})],
recommendedItems: []
};
};