carta-md
Version:
A lightweight, fully customizable, Markdown editor
259 lines (258 loc) • 7.75 kB
TypeScript
import type { Component } from 'svelte';
import { type Processor } from 'unified';
import { type Options as GfmOptions } from 'remark-gfm';
import { type Options as RehypeOptions } from 'remark-rehype';
import type { TextAreaHistoryOptions } from './history';
import { InputEnhancer } from './input';
import { type DefaultShortcutId, type KeyboardShortcut } from './shortcuts';
import { type Icon, type DefaultIconId } from './icons';
import { type DefaultPrefixId, type Prefix } from './prefixes';
import { Renderer } from './renderer';
import { CustomEvent, type MaybeArray } from './utils';
import type { Highlighter, GrammarRule, ShikiOptions, DualTheme, Theme, HighlightingRule } from './highlight';
import { type DefaultTabOutId, type TabOut } from './tabouts';
/**
* Carta-specific event with extra payload.
*/
export type Event = CustomEvent<{
carta: Carta;
}>;
declare const cartaEvents: readonly ["carta-render", "carta-render-ssr"];
type CartaEventType = (typeof cartaEvents)[number];
/**
* Custom listeners for the textarea element.
*/
export type Listener<K extends CartaEventType | keyof HTMLElementEventMap> = [
type: K,
listener: (this: HTMLTextAreaElement, ev: K extends CartaEventType ? Event : K extends keyof HTMLElementEventMap ? HTMLElementEventMap[K] : Event) => unknown,
options?: boolean | AddEventListenerOptions
];
/**
* Custom Svelte component for extensions.
*/
export interface ExtensionComponent<T extends object | undefined> {
/**
* Svelte components that exports `carta: Carta` and all the other properties specified in `props`.
*/
component: Component<T & {
carta: Carta;
}>;
/**
* Properties that will be handed to the component.
*/
props: T;
/**
* Where this component will be placed.
*/
parent: MaybeArray<'editor' | 'input' | 'renderer' | 'preview'>;
}
type Listeners = Listener<any>[];
type ExtensionComponents = Array<ExtensionComponent<any>>;
/**
* Carta editor options.
*/
export interface Options {
/**
* GitHub Flavored Markdown options.
*/
gfmOptions?: GfmOptions;
/**
* Editor/viewer extensions.
*/
extensions?: Plugin[];
/**
* Renderer debouncing timeout, in ms.
* @defaults 300ms
*/
rendererDebounce?: number;
/**
* Remove default shortcuts by ids.
*/
disableShortcuts?: DefaultShortcutId[] | true;
/**
* Remove default icons by ids.
*/
disableIcons?: DefaultIconId[] | true;
/**
* Remove default prefixes by ids.
*/
disablePrefixes?: DefaultPrefixId[] | true;
/**
* Remove default tab-outs by ids.
*/
disableTabOuts?: DefaultTabOutId[] | true;
/**
* History (Undo/Redo) options.
*/
historyOptions?: TextAreaHistoryOptions;
/**
* HTML sanitizer.
*/
sanitizer: ((html: string) => string) | false;
/**
* Highlighter options.
*/
shikiOptions?: ShikiOptions;
/**
* ShikiJS theme
* @default 'carta-light' for light mode and 'carta-dark' for dark mode.
*/
theme?: Theme | DualTheme;
/**
* Options that will be passed to rehype
*/
rehypeOptions?: RehypeOptions;
/**
* Whether to avoid capturing tab events.
*/
disableTabCapture?: boolean;
}
/**
* Unified transformers plugins.
*/
export type UnifiedTransformer<E extends 'sync' | 'async'> = {
execution: 'sync' | 'async';
type: 'remark' | 'rehype';
transform: ({ processor, carta }: {
processor: Processor;
carta: Carta;
}) => E extends 'sync' ? void : Promise<void>;
};
/**
* Carta editor extensions.
*/
export interface Plugin {
/**
* Unified transformers plugins.
* @important If the plugin is async, it will not run in SSR rendering.
*/
transformers?: UnifiedTransformer<'sync' | 'async'>[];
/**
* Additional keyboard shortcuts.
*/
shortcuts?: KeyboardShortcut[];
/**
* Additional icons.
*/
icons?: Icon[];
/**
* Additional prefixes.
*/
prefixes?: Prefix[];
/**
* Additional tab-outs.
*/
tabOuts?: TabOut[];
/**
* Textarea event listeners.
*/
listeners?: Listeners;
/**
* Additional components, that will be put after the editor.
* All components are given a `carta: Carta` prop.
* The editor has a `relative` position, so you can position
* elements absolutely.
*/
components?: ExtensionComponents;
/**
* Custom markdown grammar highlight rules for ShiKi.
*/
grammarRules?: GrammarRule[];
/**
* Custom markdown highlighting rules for ShiKi.
*/
highlightingRules?: HighlightingRule[];
/**
* Use this callback to execute code when one Carta instance loads the extension.
* @param data General Carta related data.
*/
onLoad?: (data: {
carta: Carta;
}) => void;
}
export declare class Carta {
readonly sanitizer?: (html: string) => string;
readonly historyOptions?: TextAreaHistoryOptions;
readonly theme?: Theme | DualTheme;
readonly shikiOptions?: ShikiOptions;
readonly rehypeOptions: RehypeOptions;
readonly rendererDebounce: number;
readonly keyboardShortcuts: KeyboardShortcut[];
readonly icons: Icon[];
readonly prefixes: Prefix[];
readonly tabOuts: TabOut[];
readonly grammarRules: GrammarRule[];
readonly highlightingRules: HighlightingRule[];
readonly textareaListeners: Listeners;
readonly cartaListeners: Listeners;
readonly components: ExtensionComponents;
readonly dispatcher: EventTarget;
readonly gfmOptions: GfmOptions | undefined;
readonly syncProcessor: Processor;
readonly asyncProcessor: Promise<Processor>;
readonly disableTabCapture: boolean;
private mElement;
private mInput;
private mRenderer;
private mHighlighter;
private mSyncTransformers;
private mAsyncTransformers;
get element(): HTMLDivElement | undefined;
get input(): InputEnhancer | undefined;
get renderer(): Renderer | undefined;
highlighter(): Promise<Highlighter | undefined>;
private elementsToBind;
constructor(options?: Options);
private setupSynchronousProcessor;
private setupAsynchronousProcessor;
/**
* Render markdown to html asynchronously.
* @param markdown Markdown input.
* @returns Rendered html.
*/
render(markdown: string): Promise<string>;
/**
* Render markdown, excluding syntax highlighting (SSR).
* @param markdown Markdown input.
* @returns Rendered html.
*/
renderSSR(markdown: string): string;
/**
* **Internal**: set the editor element.
* @param element The editor element.
*/
$setElement(element: HTMLDivElement): void;
/**
* **Internal**: set the input element.
* @param textarea The input textarea element.
* @param callback Update callback.
*/
$setInput(textarea: HTMLTextAreaElement, container: HTMLDivElement, callback: () => void): void;
/**
* **Internal**: set the renderer element.
* @param container Div container of the rendered element.
*/
$setRenderer(container: HTMLDivElement): void;
/**
* Bind an element to the caret position.
* @param element The element to bind.
* @param portal The portal element.
* @returns The unbind function.
*
* @example
* ```svelte
* <script>
* export let carta;
* </script>
*
* <div use:carta.bindToCaret>
* <!-- Stuff here -->
* </div>
*
* ```
*/
bindToCaret(element: HTMLElement, portal?: HTMLElement): {
destroy: () => void;
};
}
export {};