UNPKG

@atlaskit/editor-core

Version:

A package contains Atlassian editor core functionality

182 lines (163 loc) • 5.12 kB
import { NodeSpec, MarkSpec, Schema } from '../prosemirror'; import { COLOR, FONT_STYLE, SEARCH_QUERY, LINK } from './groups'; import { link, em, strong, strike, subsup, underline, code, mentionQuery, emojiQuery, textColor, } from './marks'; import { confluenceJiraIssue, confluenceUnsupportedBlock, confluenceUnsupportedInline, doc, paragraph, text, bulletList, orderedList, listItem, heading, blockquote, codeBlock, panel, rule, image, mention, media, mediaGroup, singleImage, hardBreak, emoji, table, tableCell, tableHeader, tableRow, applicationCard, decisionList, decisionItem, taskList, taskItem, unknownBlock, } from './nodes'; function addItems(builtInItems: SchemaBuiltInItem[], config: string[], customSpecs: SchemaCustomNodeSpecs | SchemaCustomMarkSpecs = {}) { if (!config) { return {}; } /** * Add built-in Node / Mark specs */ const items = builtInItems.reduce((items, { name, spec }) => { if (config.indexOf(name) !== -1) { items[name] = customSpecs[name] || spec; } return items; }, {}); /** * Add Custom Node / Mark specs */ return Object.keys(customSpecs).reduce((items, name) => { if (items[name]) { return items; } items[name] = customSpecs[name]; return items; }, items); } // We use groups to allow schemas to be constructed in different shapes without changing node/mark // specs, but this means nodes/marks are defined with groups that might never be used in the schema. // In this scenario ProseMirror will complain and prevent the schema from being constructed. // // To avoid the problem, we include items that serve to "declare" the groups in the schema. This // approach unfortunately leaves unused items in the schema, but has the benefit of avoiding the // need to manipulate `exclude` or content expression values for potentially every schema item. function groupDeclaration(name: string) { return { name: `__${name}GroupDeclaration`, spec: { group: name, } }; } const markGroupDeclarations = [ groupDeclaration(COLOR), groupDeclaration(FONT_STYLE), groupDeclaration(SEARCH_QUERY), groupDeclaration(LINK), ]; const markGroupDeclarationsNames = markGroupDeclarations.map(groupMark => groupMark.name); const nodesInOrder: SchemaBuiltInItem[] = [ { name: 'doc', spec: doc }, { name: 'paragraph', spec: paragraph }, { name: 'text', spec: text }, { name: 'bulletList', spec: bulletList }, { name: 'orderedList', spec: orderedList }, { name: 'listItem', spec: listItem }, { name: 'heading', spec: heading }, { name: 'blockquote', spec: blockquote }, { name: 'codeBlock', spec: codeBlock }, { name: 'panel', spec: panel }, { name: 'rule', spec: rule }, { name: 'image', spec: image }, { name: 'mention', spec: mention }, { name: 'media', spec: media }, { name: 'mediaGroup', spec: mediaGroup }, { name: 'singleImage', spec: singleImage }, { name: 'hardBreak', spec: hardBreak }, { name: 'emoji', spec: emoji }, { name: 'table', spec: table }, { name: 'tableCell', spec: tableCell }, { name: 'tableRow', spec: tableRow }, { name: 'tableHeader', spec: tableHeader }, { name: 'confluenceJiraIssue', spec: confluenceJiraIssue }, { name: 'confluenceUnsupportedInline', spec: confluenceUnsupportedInline }, { name: 'confluenceUnsupportedBlock', spec: confluenceUnsupportedBlock }, { name: 'applicationCard', spec: applicationCard }, { name: 'decisionList', spec: decisionList }, { name: 'decisionItem', spec: decisionItem }, { name: 'taskList', spec: taskList }, { name: 'taskItem', spec: taskItem }, { name: 'unknownBlock', spec: unknownBlock }, ]; const marksInOrder: SchemaBuiltInItem[] = [ { name: 'link', spec: link }, { name: 'em', spec: em }, { name: 'strong', spec: strong }, { name: 'strike', spec: strike }, { name: 'subsup', spec: subsup }, { name: 'underline', spec: underline }, { name: 'code', spec: code }, { name: 'mentionQuery', spec: mentionQuery }, { name: 'emojiQuery', spec: emojiQuery }, { name: 'textColor', spec: textColor }, ...markGroupDeclarations, ]; /** * Creates a schema preserving order of marks and nodes. */ export function createSchema(config: SchemaConfig): Schema<any, any> { const { nodes, customNodeSpecs, marks, customMarkSpecs } = config; const nodesConfig = Object.keys(customNodeSpecs || {}).concat(nodes); const marksConfig = Object.keys(customMarkSpecs || {}).concat(marks || []).concat(markGroupDeclarationsNames); return new Schema({ nodes: addItems(nodesInOrder, nodesConfig, customNodeSpecs), marks: addItems(marksInOrder, marksConfig, customMarkSpecs), }); } export interface SchemaConfig { nodes: string[]; customNodeSpecs?: SchemaCustomNodeSpecs; marks?: string[]; customMarkSpecs?: SchemaCustomMarkSpecs; } export interface SchemaBuiltInItem { name: string; spec: NodeSpec | MarkSpec; } export interface SchemaCustomNodeSpecs { [name: string]: NodeSpec; } export interface SchemaCustomMarkSpecs { [name: string]: MarkSpec; }