UNPKG

@atlaskit/editor-plugin-show-diff

Version:

ShowDiff plugin for @atlaskit/editor-core

159 lines (155 loc) • 4.84 kB
/** * Decoration families produced by the show-diff plugin. * Each family owns its own key space and spec shape. */ export const DecorationFamily = { diff: 'diff', anchor: 'anchor', contributorTag: 'contributor-tag' }; /** * Navigation measures the target table header and writes this variable on the * editor root immediately before scrolling. Diff decorations inherit it, so * native scrolling leaves room for the header without DOM mutation on the * ProseMirror-rendered suggestion. */ export const SCROLL_TARGET_MARGIN_CSS_PROPERTY = '--ak-editor-diff-additional-margin'; export const scrollMarginTopValue = `calc(${"var(--ds-space-400, 32px)"} + var(${SCROLL_TARGET_MARGIN_CSS_PROPERTY}, 0px))`; export const scrollMarginTopStyle = `scroll-margin-top: ${scrollMarginTopValue};`; export const AnchorTypeKey = { from: 'from', to: 'to', left: 'left', docMargin: 'doc-margin', /** The decorated block itself, which its contributor tag positions against. */ tag: 'tag' }; /** * The host widget one contributor tag renders into. Its own family, so the tag never reaches the * consumers that read diff decorations — change counting, navigation and `getDeletedWidgets`. */ /** * The diff-decoration kinds produced by the show-diff plugin. Each value is * the leading segment of the generated key, so a diff decoration's kind can be * matched with `key?.startsWith(DiffDecorationKey.inline)` etc. */ export const DiffDecorationKey = { inline: `${DecorationFamily.diff}-inline`, block: `${DecorationFamily.diff}-block`, widget: `${DecorationFamily.diff}-widget` }; export const AnchorDocMarginKey = `${DecorationFamily.anchor}-${AnchorTypeKey.docMargin}`; export const buildAnchorDecorationKey = ({ diffId, anchorType }) => { return `${DecorationFamily.anchor}-${diffId}${anchorType ? `-${anchorType}` : ''}`; }; /** * Builds a diff decoration key. The key includes the `diffId` so independently * rendered decorations for the same type remain distinguishable. */ export const buildDiffDecorationKey = ({ decorationKeyPrefix, isActive, diffId }) => `${decorationKeyPrefix}-${diffId}-${isActive ? 'active' : 'inactive'}`; export const buildDiffDecorationSpec = ({ attributionKey, colorScheme, decorationType, diffId, isActive, isInserted, leftAnchorId, nodeName, side }) => ({ decorationFamily: DecorationFamily.diff, decorationType, diffId, key: buildDiffDecorationKey({ decorationKeyPrefix: DiffDecorationKey[decorationType], diffId, isActive }), ...(attributionKey ? { attributionKey } : {}), // Active state is only needed by contributor tags, so keep it alongside an attribution key. ...(attributionKey && isActive !== undefined ? { isActive } : {}), ...(isInserted !== undefined ? { isInserted } : {}), ...(leftAnchorId ? { leftAnchorId } : {}), ...(colorScheme ? { colorScheme } : {}), ...(nodeName ? { nodeName } : {}), ...(side !== undefined ? { side } : {}) }); export function buildAnchorDecorationSpec({ anchorType, diffId, side }) { if (anchorType === AnchorTypeKey.docMargin) { return { decorationFamily: DecorationFamily.anchor, anchorType, key: AnchorDocMarginKey, ...(side !== undefined ? { side } : {}) }; } if (!diffId) { throw new Error(`diffId is required for anchor type "${anchorType}"`); } return { decorationFamily: DecorationFamily.anchor, anchorType, diffId, key: buildAnchorDecorationKey({ diffId, anchorType }), ...(side !== undefined ? { side } : {}) }; } export const buildContributorTagDecorationSpec = diffId => ({ decorationFamily: DecorationFamily.contributorTag, diffId, // Stable across recalculations, so ProseMirror keeps the host element the tag is portalled into. key: `${DecorationFamily.contributorTag}-${diffId}` }); export const isDiffDecorationSpec = spec => Boolean(spec && typeof spec === 'object' && 'decorationFamily' in spec && spec.decorationFamily === DecorationFamily.diff); export const isAnchorDecorationSpec = spec => Boolean(spec && typeof spec === 'object' && 'decorationFamily' in spec && spec.decorationFamily === DecorationFamily.anchor); export const isDiffDecoration = decoration => isDiffDecorationSpec(decoration.spec); export const extractDiffDescriptors = decorations => decorations.find(undefined, undefined, isDiffDecorationSpec).filter(isDiffDecoration).map(({ spec }) => { return { ...(spec.colorScheme ? { colorScheme: spec.colorScheme } : {}), id: spec.diffId, ...(spec.leftAnchorId ? { leftAnchorId: spec.leftAnchorId } : {}), ...(spec.isInserted !== undefined ? { isInserted: spec.isInserted } : {}), type: spec.decorationType }; });