UNPKG

@remirror/extension-code-block

Version:

Unleash the inner coder with code blocks for your remirror editor.

444 lines (417 loc) 14.7 kB
import { ApplySchemaAttributes } from '@remirror/core'; import { CommandFunction } from '@remirror/core'; import { CommandFunctionProps } from '@remirror/core'; import { CreateExtensionPlugin } from '@remirror/core'; import { Decoration } from '@remirror/pm/view'; import { DecorationSet } from '@remirror/pm/view'; import { DelayedPromiseCreator } from '@remirror/core'; import { DOMOutputSpec } from '@remirror/core'; import { EditorState } from '@remirror/core'; import { ExtensionCodeBlockTheme } from '@remirror/theme'; import type { FindProsemirrorNodeResult } from '@remirror/core'; import { InputRule } from '@remirror/core'; import { KeyBindingProps } from '@remirror/core'; import { NodeExtension } from '@remirror/core'; import { NodeExtensionSpec } from '@remirror/core'; import { NodeSpecOverride } from '@remirror/core'; import { NodeType } from '@remirror/core'; import { NodeTypeProps } from '@remirror/core'; import { NodeWithPosition } from '@remirror/core'; import { NonChainableCommandFunction } from '@remirror/core'; import { OnSetOptionsProps } from '@remirror/core'; import { Positioner } from '@remirror/extension-positioner'; import { PosProps } from '@remirror/core'; import { ProsemirrorAttributes } from '@remirror/core'; import { ProsemirrorNode } from '@remirror/core'; import type { RefractorSyntax } from 'refractor/core.js'; import type { Static } from '@remirror/core'; import type { StringKey } from '@remirror/core'; import { Transaction } from '@remirror/core'; declare interface CodeBlockAttributes extends ProsemirrorAttributes { /** * The language attribute */ language: string; /** * Set to true to active the wrapping of the content within the editor. */ wrap?: boolean; } export { CodeBlockAttributes } export { CodeBlockAttributes as CodeBlockAttributes_alias_1 } declare class CodeBlockExtension extends NodeExtension<CodeBlockOptions> { get name(): "codeBlock"; createTags(): ("code" | "block")[]; /** * Add the languages to the environment if they have not yet been added. */ protected init(): void; createNodeSpec(extra: ApplySchemaAttributes, override: NodeSpecOverride): NodeExtensionSpec; /** * Add the syntax theme class to the editor. */ createAttributes(): ProsemirrorAttributes; /** * Create an input rule that listens converts the code fence into a code block * when typing triple back tick followed by a space. */ createInputRules(): InputRule[]; protected onSetOptions(props: OnSetOptionsProps<CodeBlockOptions>): void; /** * Create the custom code block plugin which handles the delete key amongst other things. */ createPlugin(): CreateExtensionPlugin<CodeBlockState>; /** * Call this method to toggle the code block. * * @remarks * * ```ts * actions.toggleCodeBlock({ language: 'ts' }); * ``` * * The above makes the current node a codeBlock with the language ts or * remove the code block altogether. */ toggleCodeBlock(attributes?: Partial<CodeBlockAttributes>): CommandFunction; /** * Creates a code at the current position. * * ```ts * commands.createCodeBlock({ language: 'js' }); * ``` */ createCodeBlock(attributes: CodeBlockAttributes): CommandFunction; /** * Update the code block at the current position. Primarily this is used * to change the language. * * ```ts * if (commands.updateCodeBlock.enabled()) { * commands.updateCodeBlock({ language: 'markdown' }); * } * ``` */ updateCodeBlock(attributes: CodeBlockAttributes): CommandFunction; /** * Format the code block with the code formatting function passed as an * option. * * Code formatters (like prettier) add a lot to the bundle size and hence * it is up to you to provide a formatter which will be run on the entire * code block when this method is used. * * ```ts * if (actions.formatCodeBlock.enabled()) { * actions.formatCodeBlock(); * // Or to format a separate code block via position * actions.formatCodeBlock({ pos: 100 }); * } * ``` */ formatCodeBlock({ pos }?: Partial<PosProps>): NonChainableCommandFunction; tabKey({ state, dispatch }: KeyBindingProps): boolean; backspaceKey({ dispatch, tr, state }: KeyBindingProps): boolean; enterKey({ dispatch, tr }: KeyBindingProps): boolean; formatShortcut({ tr }: KeyBindingProps): boolean; /** * Register passed in languages. */ private registerLanguages; /** * Create delayed format command. */ private readonly createFormatCodeBlockCommand; } export { CodeBlockExtension } export { CodeBlockExtension as CodeBlockExtension_alias_1 } /** * A function which takes code and formats the code. * * TODO - possibly allow error management if failure is because of invalid * syntax */ declare type CodeBlockFormatter = (params: FormatterProps) => Promise<FormattedContent | void>; export { CodeBlockFormatter } export { CodeBlockFormatter as CodeBlockFormatter_alias_1 } declare interface CodeBlockOptions { /** * Import languages from refractor. * * @remarks * * ```ts * import jsx from 'refractor/lang/jsx.js' * import typescript from 'refractor/lang/typescript.js' * ``` * * And pass them into the config when initializing this extension. * * ```ts * import { CodeBlockExtension } from '@remirror/extension-code-block'; * * new CodeBlockExtension({ supportedLanguages: [typescript, jsx] }) * ``` * * Or as a component * * ```tsx * <RemirrorManager> * <RemirrorExtension Constructor={CodeBlockExtension} supportedLanguages={[typescript, jsx]} /> * </RemirrorManager> * ``` * * By default refractor bundles the following languages: `markup`, `css`, * `clike`, `js` * * @defaultValue [] */ supportedLanguages?: RefractorSyntax[]; /** * The default language to use when none is provided. * * It is a property so it can change during the editor's life. * * @defaultValue 'markup' */ defaultLanguage?: string; /** * Set to true to wrap content by default. * * @defaultValue false */ defaultWrap?: boolean; /** * The theme to use for the codeBlocks. * * @remarks * * Currently only one theme can be set per editor. * * Set this to false if you want to manage the syntax styles by yourself. For * tips on how this could be accomplished see {@link https://prismjs.com} * * @defaultValue 'atom-dark' */ syntaxTheme?: SyntaxTheme; /** * Provide a formatter which can format the provided source code. * * @returns an object when formatting was successful and false when the code * could not be formatted (a noop). */ formatter?: CodeBlockFormatter; /** * The name of the node that the code block should toggle back and forth from. * * @defaultValue 'paragraph' */ toggleName?: string; /** * Class to use in decorations of plain `text` nodes. * * @remarks * * refractor highlighting produces `elements` to indicate the type of a part * of the code. These elements get translated into decorations by this plugin. * * For all other parts of the code the decoration will use this class name if * it is set to a non-empty value, otherwise no decoration will be produced. */ plainTextClassName?: string; /** * Extract the language string from a code block. */ getLanguageFromDom?: Static<(codeElement: HTMLElement, preElement: HTMLElement) => string | undefined>; } export { CodeBlockOptions } export { CodeBlockOptions as CodeBlockOptions_alias_1 } declare const codeBlockPositioner: Positioner<FindProsemirrorNodeResult>; export { codeBlockPositioner } export { codeBlockPositioner as codeBlockPositioner_alias_1 } export declare class CodeBlockState { #private; /** * The set of cached decorations to minimize dom updates */ decorationSet: DecorationSet; constructor(type: NodeType, extension: NodeExtension<CodeBlockOptions>); /** * Creates the initial set of decorations */ init(state: EditorState): this; /** * Recreate all the decorations again for all the provided blocks. */ private refreshDecorationSet; /** * Apply the state and update decorations when a change has happened in the * editor. */ apply(tr: Transaction, _: EditorState): this; /** * Removes all decorations which relate to the changed block node before creating new decorations * and adding them to the decorationSet. */ private updateDecorationSet; /** * Flags that a deletion has just occurred. */ setDeleted(deleted: boolean): void; } /** * Used to provide a `toDom` function for the code block. Currently this only * support the browser runtime. */ export declare function codeBlockToDOM(node: ProsemirrorNode, extra: ApplySchemaAttributes): DOMOutputSpec; /** * Creates a decoration set for the provided blocks */ export declare function createDecorations(props: CreateDecorationsProps): Decoration[]; declare interface CreateDecorationsProps { defaultLanguage: string; /** * The list of codeBlocks and their positions which we would like to update. */ blocks: NodeWithPosition[]; /** * When a delete happens within the last valid decoration in a block it causes * the editor to jump. This skipLast should be set to true immediately after a * delete which then allows for createDecorations to skip updating the * decoration for the last refactor node, and hence preventing the jumpy bug. */ skipLast: boolean; plainTextClassName: string | undefined; } export declare interface DelayedFormatCodeBlockProps<Value> { /** * Optionally specify a position to identify a code block. */ pos?: PosProps['pos']; /** * A function that returns a promise. */ promise: DelayedPromiseCreator<Value>; /** * Called when the promise succeeds and the formatted code is available. If * formatting fails, the failure handler is called instead. */ onSuccess: (value: Value, commandProps: CommandFunctionProps) => boolean; /** * Called when a failure is encountered. */ onFailure?: CommandFunction<{ error: unknown; }>; } /** * Format the contents of a selected codeBlock or one located at the provided * position. */ export declare function formatCode(props: FormatCodeProps): Promise<FormatCodeResult | undefined>; declare type FormatCodeProps = NodeTypeProps & Required<Pick<CodeBlockOptions, 'formatter' | 'defaultLanguage'>> & Partial<PosProps> & CommandFunctionProps; export declare interface FormatCodeResult { /** * Formatted code */ formatted: string; /** * The original range that should be replaced in the code block */ range: { from: number; to: number; }; /** * Updated selection coordinates for the formatted code */ selection: { anchor: number; head?: number; }; } /** * Data returned from a code formatter. */ declare interface FormattedContent { /** * The transformed source. */ formatted: string; /** * The new cursor position after formatting */ cursorOffset: number; } export { FormattedContent } export { FormattedContent as FormattedContent_alias_1 } /** * A prettier based code formatter which can be dropped in for use within the * `CodeBlockExtension`. */ export declare function formatter(props: FormatterProps): Promise<FormattedContent | undefined>; declare interface FormatterProps { /** * The code to be formatted */ source: string; /** * Specify where the cursor is. This option cannot be used with rangeStart and * rangeEnd. This allows the command to both formats the code, and translates * a cursor position from unformatted code to formatted code. */ cursorOffset: number; /** * The language of the code block. Should be used to determine whether the * formatter can support the transformation. * * Possible languages are available here * https://github.com/wooorm/refractor/tree/716fe904c37cd7ebfde53ac5157e7d6c323a3986/lang */ language: string; } export { FormatterProps } export { FormatterProps as FormatterProps_alias_1 } /** * Get the language from user input. */ declare function getLanguage(props: GetLanguageProps): string; export { getLanguage } export { getLanguage as getLanguage_alias_1 } export { getLanguage as getLanguage_alias_2 } /** * Get the language from the provided `code` element. This is used as the * default implementation in the `CodeExtension` but it can be overridden. */ export declare function getLanguageFromDom(codeElement: HTMLElement): string | undefined; declare interface GetLanguageProps { /** * The language input from the user; */ language: string | undefined; /** * The default language to use if none found. */ fallback: string; } /** * Check that the attributes exist and are valid for the codeBlock * updateAttributes. */ export declare function isValidCodeBlockAttributes(attributes: ProsemirrorAttributes): attributes is CodeBlockAttributes; export declare const LANGUAGE_ATTRIBUTE = "data-code-block-language"; /** * The default supported syntax themes. */ declare type SyntaxTheme = Lowercase<StringKey<typeof ExtensionCodeBlockTheme>>; export { SyntaxTheme } export { SyntaxTheme as SyntaxTheme_alias_1 } export declare const toggleCodeBlockOptions: Remirror.CommandDecoratorOptions; /** * Updates the node attrs. * * This is used to update the language for the codeBlock. */ export declare function updateNodeAttributes(type: NodeType): (attributes: CodeBlockAttributes) => CommandFunction; export declare const WRAP_ATTRIBUTE = "data-code-block-wrap"; export { }