wysiwyg4all
Version:
Free opensource minimal WYSIWYG editor for web developers
258 lines (256 loc) • 8.13 kB
TypeScript
type EditorFontSize = {
desktop?: number | string;
tablet?: number | string;
phone?: number | string;
h1?: number | string;
h2?: number | string;
h3?: number | string;
h4?: number | string;
h5?: number | string;
h6?: number | string;
small?: number | string;
};
type ColorScheme = Record<string, string>;
type BuiltInCommand = "quote" | "unorderedList" | "orderedList" | "divider" | "image" | "alignLeft" | "alignCenter" | "alignRight" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "small" | "bold" | "italic" | "underline" | "strike" | "color";
type CommandObject = {
element?: HTMLElement | string;
elementId?: string;
style?: Partial<CSSStyleDeclaration> & Record<string, string>;
insert?: boolean;
backgroundColor?: string;
color?: string;
};
type CommandInput = BuiltInCommand | CommandObject | string;
type CommandTracker = {
"unorderedList": boolean;
"orderedList": boolean;
"alignLeft": boolean;
"alignCenter": boolean;
"alignRight": boolean;
"h1": boolean;
"h2": boolean;
"h3": boolean;
"h4": boolean;
"h5": boolean;
"h6": boolean;
"small": boolean;
"bold": boolean;
"italic": boolean;
"underline": boolean;
"strike": boolean;
"color": string;
"backgroundColor": string;
};
type ImageData = {
elementId: string;
source: string;
filename?: string;
fileType?: string;
fileSize?: number;
lastModified?: number;
dimension?: {
width: number;
height: number;
};
element?: HTMLImageElement;
class?: string[];
style?: Record<string, string>;
onclick?: (ev: MouseEvent) => void;
};
type HashtagData = {
elementId: string;
tag: string;
element?: HTMLSpanElement;
style?: Record<string, string>;
onclick?: (ev: MouseEvent) => void;
};
type UrlData = {
elementId: string;
url: string;
element?: HTMLSpanElement;
style?: Record<string, string>;
onclick?: (ev: MouseEvent) => void;
};
type CustomData = {
elementId: string;
element: HTMLElement;
};
type CallbackPayload = {
commandTracker?: CommandTracker;
range?: Range | null;
caratPosition?: DOMRect | null;
loading?: boolean;
image?: ImageData[];
hashtag?: HashtagData[];
urllink?: UrlData[];
};
type ExportPayload = {
html: string;
title: string;
text: string;
urllink?: UrlData[];
hashtag?: HashtagData[];
image: ImageData[];
custom: CustomData[];
};
type ExtensionApi = {
registerCommand: (name: string, handler: (editor: Wysiwyg4All, action: CommandInput) => void | Promise<void>) => void;
on: (eventName: string, handler: (...args: unknown[]) => void) => () => void;
editor: Wysiwyg4All;
};
type ExtensionFactory = (api: ExtensionApi) => void;
type ExportSetup = {
dom: HTMLElement;
urllink?: UrlData[];
hashtag?: HashtagData[];
image: ImageData[];
custom: CustomData[];
title?: string;
};
type Wysiwyg4AllOptions = {
elementId: string;
editable?: boolean;
placeholder?: string;
spellcheck?: boolean;
highlightColor?: string | ColorScheme;
html?: string;
callback?: (payload: CallbackPayload) => CallbackPayload | Promise<CallbackPayload>;
fontSize?: EditorFontSize | number;
hashtag?: boolean;
urllink?: boolean;
extensions?: ExtensionFactory[];
};
declare class Wysiwyg4All {
private readonly option;
private readonly element;
private readonly styleTagOfCommand;
private readonly customCommandHandlers;
private readonly eventBus;
private readonly imageInput;
private observer;
private range;
private rangeBackup;
private callback;
private readonly hashtagEnabled;
private readonly urlEnabled;
private lastKey;
private suspendSelectionCaptureForColorPicker;
private colorCommandDebounceTimer;
private pendingColorCommand;
private pendingColorSelectionSnapshot;
private trackerUpdateInFlight;
private trackerUpdateQueued;
private livePickerColor;
private livePickerBackgroundColor;
private colorPickerInteractionUntil;
highlightColor: string;
defaultFontColor: string;
defaultBackgroundColor: string;
image_array: ImageData[];
hashtag_array: HashtagData[];
urllink_array: UrlData[];
custom_array: CustomData[];
commandTracker: CommandTracker;
constructor(option: Wysiwyg4AllOptions);
private initializeCommandTracker;
private applyTheme;
private applyFontSize;
private bindCoreEvents;
private unbindCoreEvents;
private bootstrapExtensions;
private emit;
private onWindowMouseDown;
private onSelectionChange;
private onKeyDown;
private onPaste;
private ensureRootHasSafeLine;
private createEmptyParagraph;
private setSelectionAtStart;
private isLineVisuallyEmpty;
private isNonTextElement;
private getContainingQuote;
private unwrapQuote;
private getQuoteLineBlocks;
private handleEnterFromQuoteTail;
private handleDeleteFromTrailingEmptyLine;
private captureRange;
private isCollapsedStyleAnchorSpan;
private reanchorCollapsedRangeToAdjacentStylePlaceholder;
private backupCurrentRange;
private getTextOffsetWithinEditor;
private resolveBoundaryFromTextOffset;
private snapshotRangeToTextOffsets;
private restoreRangeFromTextOffsets;
private getDeepBoundaryPoint;
private resolveRangeBoundaryPoint;
private normalizeEditorRange;
private restoreLastSelection;
setPlaceholder(placeholder: string): void;
setSpellcheck(enabled: boolean): void;
setEditable(enabled: boolean): void;
private isEditorInPlaceholderState;
private updatePlaceholderVisibility;
destroy(): void;
private observeMutation;
private isUnSelectableElement;
private isTextBlockElement;
private isCeilingElement;
private cleanupZeroWidthSpaces;
private normalizeDocument;
private isLineBlockElement;
private cloneInlineStyleSpan;
private getContainingLineBlock;
private getLineBlocksBetween;
private doesRangeIntersectElement;
private getSelectedLineBlocks;
private createLineIntersectionRange;
private applyStyleToRange;
private wrapMultilineSelectionWithClass;
private redistributeInlineStylesAcrossBlocks;
private isFontSizeClassName;
private getElementFontSizeClass;
private findOutermostFontSizeAncestor;
private cleanupNestedFontSizeWrappers;
private hasMeaningfulAttributes;
private hasNonClassStyleAttributes;
private isProtectedSpan;
private cleanupRedundantTextWrappers;
private isTextStyleWrapper;
private cleanupEmptyTextStyleElements;
private setSelectionAtEnd;
private splitRangeBoundaries;
private getKnownInlineStyleClassSet;
private findClosestAncestorWithClass;
private findOutermostAncestorWithClass;
private collectPreservedInlineStyles;
private liftNodeOneLevel;
private breakOutFromAncestor;
private stripSameStyleFromFragment;
private wrapSelectionWithClass;
private removeCounterClasses;
private isStyleAppliedToSelection;
private removeStyleFromSelection;
private applyAlignment;
private getClosestLine;
private insertNodeAtSelection;
private ensureCaretAfterNonTextElement;
private ensureTrailingEditableLineAfter;
private insertText;
private onImageSelected;
private readFileAsDataUrl;
private readImageDimension;
private safeCallback;
private resolveSpanByData;
private applySpanDecorators;
private isTransparentComputedColor;
private resolveTrackerTextColor;
private resolveTrackerBackgroundColor;
private updateCommandTracker;
private flushCommandTrackerUpdates;
private runCommandTrackerUpdate;
private scanSpecialTokens;
command(action: CommandInput): Promise<void>;
loadHTML(html: string, editable?: boolean): Promise<void>;
export(pre?: (setup: ExportSetup) => ExportSetup | Promise<ExportSetup>): Promise<ExportPayload>;
}
export { Wysiwyg4All, type Wysiwyg4AllOptions };