@atlaskit/editor-plugin-code-block-advanced
Version:
CodeBlockAdvanced plugin for @atlaskit/editor-core
113 lines (112 loc) • 5.1 kB
JavaScript
import { codeBlock, codeBlockWithExtendedAttributes, codeBlockWithLocalId } from '@atlaskit/adf-schema';
import { areCodeBlockLineNumbersHidden } from '@atlaskit/editor-common/code-block';
import { convertToInlineCss } from '@atlaskit/editor-common/lazy-node-view';
import { CodeBlockSharedCssClassName } from '@atlaskit/editor-common/styles';
import { fg } from '@atlaskit/platform-feature-flags';
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
const codeBlockClassNames = {
container: CodeBlockSharedCssClassName.CODEBLOCK_CONTAINER,
start: CodeBlockSharedCssClassName.CODEBLOCK_START,
end: CodeBlockSharedCssClassName.CODEBLOCK_END,
contentWrapper: CodeBlockSharedCssClassName.CODEBLOCK_CONTENT_WRAPPER,
contentWrapped: CodeBlockSharedCssClassName.CODEBLOCK_CONTENT_WRAPPED,
content: CodeBlockSharedCssClassName.CODEBLOCK_CONTENT
};
const MATCH_NEWLINES = new RegExp('\n', 'gu');
const getFontSize = () => expValEquals('confluence_compact_text_format', 'isEnabled', true) || expValEquals('cc_editor_ai_content_mode', 'variant', 'test') && fg('platform_editor_content_mode_button_mvp') ? '0.875em' : '0.875rem';
const getGutterBaseStyle = () => ({
backgroundColor: "var(--ds-background-neutral, #0515240F)",
position: 'relative',
flexShrink: 0,
// eslint-disable-next-line @atlaskit/design-system/use-tokens-typography
fontSize: getFontSize(),
boxSizing: 'content-box'
});
const getGutterPadding = allowCodeFolding => allowCodeFolding ? `${"var(--ds-space-100, 8px)"} ${"var(--ds-space-250, 20px)"} ${"var(--ds-space-100, 8px)"} ${"var(--ds-space-075, 6px)"}` : "var(--ds-space-100, 8px)";
const getGuttersWithLineNumbers = (content, config) => ['div', {
// Based on packages/editor/editor-common/src/styles/shared/code-block.ts
// But we can't reuse that class as it adds a ::before that intefers with this approach
style: convertToInlineCss({
...getGutterBaseStyle(),
width: 'var(--lineNumberGutterWidth, 2rem)',
/* top and bottom | left and right */
padding: getGutterPadding(config.allowCodeFolding)
}),
contenteditable: 'false'
}, ['div', {
class: 'code-block-gutter-pseudo-element',
style: convertToInlineCss({
textAlign: 'right',
color: "var(--ds-text-subtlest, #6B6E76)",
fontFamily: "var(--ds-font-family-code, \"Atlassian Mono\", ui-monospace, Menlo, \"Segoe UI Mono\", \"Ubuntu Mono\", monospace)",
whiteSpace: 'pre-wrap'
}),
'data-label': content
}]];
const getFoldOnlyGutter = () => ['div', {
style: convertToInlineCss({
...getGutterBaseStyle(),
padding: `${"var(--ds-space-100, 8px)"} ${"var(--ds-space-150, 12px)"} ${"var(--ds-space-100, 8px)"} ${"var(--ds-space-100, 8px)"}`
}),
contenteditable: 'false'
}];
const getGutters = (content, config, hideLineNumbers) => {
if (!hideLineNumbers) {
return [getGuttersWithLineNumbers(content, config)];
}
if (config.allowCodeFolding) {
return [getFoldOnlyGutter()];
}
return [];
};
// Based on: `packages/editor/editor-plugin-code-block/src/nodeviews/code-block.ts`
const toDOM = (node, formattedAriaLabel, config) => {
let totalLineCount = 1;
node.forEach(node => {
const text = node.text;
if (text) {
totalLineCount += (node.text.match(MATCH_NEWLINES) || []).length;
}
});
const hideLineNumbers = areCodeBlockLineNumbersHidden(node);
const maxDigits = totalLineCount.toString().length;
const content = node.textContent.split('\n').map((_, i) => i + 1).join('\n');
const gutters = getGutters(content, config, hideLineNumbers);
const isCodeBlockWrapped = expValEquals('platform_editor_code_block_q4_lovability', 'isEnabled', true) && node.attrs.wrap === true;
const className = [codeBlockClassNames.container, isCodeBlockWrapped ? codeBlockClassNames.contentWrapped : undefined].filter(Boolean).join(' ');
return ['pre', {
class: className,
style: `--lineNumberGutterWidth:${maxDigits}ch;`,
'data-language': node.attrs.language || '',
...(expValEquals('platform_editor_code_block_q4_lovability', 'isEnabled', true) && {
'data-wrap': node.attrs.wrap ? 'true' : 'false',
...(hideLineNumbers && {
'data-hide-line-numbers': 'true'
})
})
}, ['div', {
class: codeBlockClassNames.start,
contenteditable: 'false'
}], ['div', {
class: codeBlockClassNames.contentWrapper
}, ...gutters, ['div', {
class: codeBlockClassNames.content
}, ['code', {
'data-language': node.attrs.language || '',
spellcheck: 'false',
'data-testid': 'code-block--code',
'aria-label': formattedAriaLabel,
...(fg('platform_editor_adf_with_localid') && {
'data-local-id': node.attrs.localId
})
}, 0]]], ['div', {
class: codeBlockClassNames.end,
contenteditable: 'false'
}]];
};
export const codeBlockNodeWithFixedToDOM = config => {
return {
...(expValEquals('platform_editor_code_block_q4_lovability', 'isEnabled', true) ? codeBlockWithExtendedAttributes : fg('platform_editor_adf_with_localid') ? codeBlockWithLocalId : codeBlock),
toDOM: node => toDOM(node, '', config)
};
};