UNPKG

@atlaskit/editor-plugin-code-block-advanced

Version:

CodeBlockAdvanced plugin for @atlaskit/editor-core

190 lines (180 loc) 6.2 kB
import type { Extension } from '@codemirror/state'; import { EditorView as CodeMirror } from '@codemirror/view'; import type { EditorContentMode } from '@atlaskit/editor-common/types'; import { fg } from '@atlaskit/platform-feature-flags'; import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals'; import { token } from '@atlaskit/tokens'; const shouldUseCompactTypography = (contentMode?: EditorContentMode) => contentMode === 'compact' || (expValEquals('cc_editor_ai_content_mode', 'variant', 'test') && fg('platform_editor_content_mode_button_mvp')); const getLineHeight = (contentMode?: EditorContentMode) => shouldUseCompactTypography(contentMode) ? '1.5em' : '1.5rem'; const getFontSize = (contentMode?: EditorContentMode) => shouldUseCompactTypography(contentMode) ? '0.875em' : '0.875rem'; type ThemeOptions = { contentMode?: EditorContentMode; }; export const cmTheme = (options?: ThemeOptions): Extension => CodeMirror.theme({ '&': { backgroundColor: token('color.background.neutral'), padding: '0', marginTop: token('space.100'), marginBottom: token('space.100'), // eslint-disable-next-line @atlaskit/design-system/use-tokens-typography fontSize: getFontSize(options?.contentMode), // Custom syntax styling to match existing styling // eslint-disable-next-line @atlaskit/design-system/use-tokens-typography lineHeight: getLineHeight(options?.contentMode), }, '&.cm-focused': { outline: 'none', }, '.cm-line': { padding: '0', }, '&.cm-editor.code-block.danger': { backgroundColor: token('color.background.danger'), }, '.cm-content[aria-readonly="true"]': { caretColor: 'transparent', }, '.cm-content': { cursor: 'text', caretColor: token('color.text'), margin: token('space.100'), padding: token('space.0'), }, '.cm-scroller': { backgroundColor: token('color.background.neutral'), // Custom syntax styling to match existing styling // eslint-disable-next-line @atlaskit/design-system/use-tokens-typography lineHeight: 'unset', fontFamily: token('font.family.code'), borderRadius: token('radius.small'), backgroundImage: overflowShadow({ leftCoverWidth: token('space.300'), }), backgroundAttachment: 'local, local, local, local, scroll, scroll, scroll, scroll', }, '&.cm-focused .cm-cursor': { borderLeftColor: token('color.text'), }, '.cm-gutter': { padding: token('space.100'), }, '.cm-gutters': { backgroundColor: token('color.background.neutral'), border: 'none', padding: token('space.0'), color: token('color.text.subtlest'), ...(expValEquals('platform_editor_code_block_q4_lovability', 'isEnabled', true) && { // CodeMirror defaults this to height: 100%, which can resolve against an indefinite // parent height in content-height editor and prevent flex stretching when gutter // content is sparse, such as fold-only gutters. height: 'unset', alignSelf: 'stretch', }), }, '.cm-lineNumbers .cm-gutterElement': { paddingLeft: token('space.0'), paddingRight: token('space.0'), minWidth: 'unset', }, // Set the gutter element min height to prevent flicker of styling while // codemirror is calculating (which happens after an animation frame). // Example problem: https://github.com/codemirror/dev/issues/1076 // Ignore the first gutter element as it is a special hidden element. '.cm-gutterElement:not(:first-child)': { // eslint-disable-next-line @atlaskit/design-system/use-tokens-typography minHeight: getLineHeight(options?.contentMode), }, }); export const codeFoldingTheme: Extension = CodeMirror.theme({ '.cm-gutter': { paddingLeft: token('space.075'), paddingTop: token('space.100'), paddingBottom: token('space.100'), paddingRight: token('space.0'), }, '.cm-foldGutter': { paddingLeft: token('space.050'), }, '.cm-gutterElement:has([data-marker-dom-element="true"])': { color: token('color.icon.subtle'), }, '.cm-gutterElement:has([data-marker-dom-element="true"]):hover': { color: token('color.text.accent.gray.bolder'), }, '.cm-foldPlaceholder': { // To give spacing between lines height: '20px', backgroundColor: token('color.background.accent.gray.subtlest'), border: 'none', color: token('color.text'), outline: `1px solid ${token('color.border.accent.gray')}`, paddingLeft: token('space.025'), paddingRight: token('space.025'), }, '.cm-foldPlaceholder:hover': { backgroundColor: token('color.background.accent.gray.subtlest.hovered'), }, }); /** * Copied directly from `packages/editor/editor-shared-styles/src/overflow-shadow/overflow-shadow.ts` * `CodeMirror` does not support emotion styling so this has been re-created. */ function overflowShadow({ leftCoverWidth, rightCoverWidth, }: { leftCoverWidth?: string; rightCoverWidth?: string; }) { const width = token('space.100'); const leftCoverWidthResolved = leftCoverWidth || width; const rightCoverWidthResolved = rightCoverWidth || width; return ` linear-gradient( to right, ${token('color.background.neutral')} ${leftCoverWidthResolved}, transparent ${leftCoverWidthResolved} ), linear-gradient( to right, ${token('elevation.surface.raised')} ${leftCoverWidthResolved}, transparent ${leftCoverWidthResolved} ), linear-gradient( to left, ${token('color.background.neutral')} ${rightCoverWidthResolved}, transparent ${rightCoverWidthResolved} ), linear-gradient( to left, ${token('elevation.surface.raised')} ${rightCoverWidthResolved}, transparent ${rightCoverWidthResolved} ), linear-gradient( to left, ${token('elevation.shadow.overflow.spread')} 0, ${token('utility.UNSAFE.transparent')} ${width} ), linear-gradient( to left, ${token('elevation.shadow.overflow.perimeter')} 0, ${token('utility.UNSAFE.transparent')} ${width} ), linear-gradient( to right, ${token('elevation.shadow.overflow.spread')} 0, ${token('utility.UNSAFE.transparent')} ${width} ), linear-gradient( to right, ${token('elevation.shadow.overflow.perimeter')} 0, ${token('utility.UNSAFE.transparent')} ${width} ) `; }