UNPKG

@dsfr-builder/grapesjs

Version:

Free and Open Source Web Builder Framework

1,577 lines (1,575 loc) 424 kB
import Backbone from 'backbone'; import { ModelDestroyOptions, _StringKey } from 'backbone'; export interface DomComponentsConfig { stylePrefix?: string; /** * Could be used for default components. */ components?: Record<string, any>[]; /** * If the component is draggable you can drag the component itself (not only from the toolbar). * @default true */ draggableComponents?: boolean; /** * Experimental: Disable text inner components. * With this option, you're able to decide which inner component inside text should be * disabled (eg. no select, no hover, no layer visibility) once edited. * @default false * @example * // disable all inner childs * disableTextInnerChilds: true, * // disable all except link components * disableTextInnerChilds: (child) => !child.is('link'), */ disableTextInnerChilds?: boolean | ((cmp: Component) => boolean | void); /** * You can setup a custom component definition processor before adding it into the editor. * It might be useful to transform custom objects (es. some framework specific JSX) to GrapesJS component one. * This custom function will be executed on ANY new added component to the editor so make smart checks/conditions * to avoid doing useless executions * By default, GrapesJS supports already elements generated from React JSX preset * @example * processor: (obj) => { * if (obj.$$typeof) { // eg. this is a React Element * const gjsComponent = { * type: obj.type, * components: obj.props.children, * ... * }; * ... * return gjsComponent; * } * } */ processor?: (obj: any) => Record<string, any> | undefined; /** * List of HTML void elements. * https://www.w3.org/TR/2011/WD-html-markup-20110113/syntax.html#void-elements */ voidElements?: string[]; /** * Experimental: Use the frame document for DOM element creation. * This option might be useful when elements require the local document context to * work properly (eg. Web Components). */ useFrameDoc?: boolean; } declare class ModuleModel<TModule extends IBaseModule<any> = Module, T extends ObjectHash = any, S = SetOptions, E = any> extends Model<T, S, E> { private _module; constructor(module: TModule, attributes?: T, options?: CombinedModelConstructorOptions<E>); get module(): TModule; get config(): TModule extends IBaseModule<infer C> ? C : unknown; get em(): EditorModel; } export type ModuleExt<TModel extends ModuleModel> = TModel extends ModuleModel<infer M> ? M : unknown; export type ModelConstructor<TModel extends ModuleModel> = { new (mod: ModuleExt<TModel>, attr: any): TModel; }; declare class ModuleCollection<TModel extends ModuleModel = ModuleModel> extends Collection<TModel> { module: ModuleExt<TModel>; private newModel; add(model: Array<Record<string, any>> | TModel, options?: AddOptions): TModel; add(models: Array<Array<Record<string, any>> | TModel>, options?: AddOptions): TModel[]; constructor(module: ModuleExt<TModel>, models: TModel[] | Array<Record<string, any>>, modelConstructor: ModelConstructor<TModel>); preinitialize(models?: TModel[] | Array<Record<string, any>>, options?: any): void; } export type ModuleFromModel<TModel extends ModuleModel> = TModel extends ModuleModel<infer M> ? M : unknown; export type ModuleModelExt<TItem extends ModuleModel | ModuleCollection> = TItem extends ModuleCollection<infer M> ? ModuleFromModel<M> : TItem extends ModuleModel<infer M> ? M : unknown; declare class ModuleView<TModel extends ModuleModel | ModuleCollection = ModuleModel, TElement extends Element = HTMLElement> extends View<TModel extends ModuleModel ? TModel : undefined, TElement> { protected get pfx(): string; protected get ppfx(): string; collection: TModel extends ModuleModel ? ModuleCollection<ModuleModel> : TModel; protected get module(): ModuleModelExt<TModel>; protected get em(): EditorModel; protected get config(): ModuleModelExt<TModel> extends IBaseModule<infer C> ? C : unknown; className: string; preinitialize(options?: any): void; } export type ContentElement = string | ComponentDefinition; export type ContentType = ContentElement | ContentElement[]; export interface DraggableContent { /** * Determines if a block can be moved inside a given component when the content is a function. * * This property is used to determine the validity of the drag operation. * @type {ComponentDefinition | undefined} */ dragDef?: ComponentDefinition; /** * The content being dragged. Might be an HTML string or a [Component Defintion](/modules/Components.html#component-definition) */ content?: ContentType | (() => ContentType); } export type DragSource<T> = DraggableContent & { model?: T; }; export type Placement = "inside" | "before" | "after"; export type DroppableZoneConfig = { ratio: number; minUndroppableDimension: number; maxUndroppableDimension: number; }; declare enum DragDirection { Vertical = "Vertical", Horizontal = "Horizontal", BothDirections = "BothDirections" } export type CustomTarget = ({ event }: { event: MouseEvent; }) => HTMLElement | null; export interface SorterContainerContext { container: HTMLElement; containerSel: string; itemSel: string; pfx: string; document: Document; placeholderElement: HTMLElement; customTarget?: CustomTarget; } export interface PositionOptions { windowMargin?: number; borderOffset?: number; offsetTop?: number; offsetLeft?: number; canvasRelative?: boolean; relative?: boolean; } /** * Represents an event handler for the `onStartSort` event. * * @param sourceNodes The source nodes being sorted. * @param container The container element where the sorting is taking place. */ export type OnStartSortHandler<NodeType> = (sourceNodes: NodeType[], container?: HTMLElement) => void; /** * Represents an event handler for the `onDragStart` event. * * @param mouseEvent The mouse event associated with the drag start. */ export type OnDragStartHandler = (mouseEvent: MouseEvent) => void; export type OnMouseMoveHandler = (mouseEvent: MouseEvent) => void; export type OnDropHandler<NodeType> = (targetNode: NodeType | undefined, sourceNodes: NodeType[], index: number | undefined) => void; export type OnTargetChangeHandler<NodeType> = (oldTargetNode: NodeType | undefined, newTargetNode: NodeType | undefined) => void; export type OnPlaceholderPositionChangeHandler = (targetDimension: Dimension, placement: Placement) => void; export type OnEndHandler = () => void; /** * Represents a collection of event handlers for sortable tree node events. */ export interface SorterEventHandlers<NodeType> { onStartSort?: OnStartSortHandler<NodeType>; onDragStart?: OnDragStartHandler; onMouseMove?: OnMouseMoveHandler; onDrop?: OnDropHandler<NodeType>; onTargetChange?: OnTargetChangeHandler<NodeType>; onPlaceholderPositionChange?: OnPlaceholderPositionChangeHandler; onEnd?: OnEndHandler; legacyOnMoveClb?: Function; legacyOnStartSort?: Function; legacyOnEndMove?: Function; legacyOnEnd?: Function; } export interface SorterDragBehaviorOptions { dragDirection: DragDirection; nested?: boolean; selectOnEnd?: boolean; } export interface SorterOptions<T, NodeType extends SortableTreeNode<T>> { em: EditorModel; treeClass: new (model: T, dragSource?: DragSource<T>) => NodeType; containerContext: SorterContainerContext; positionOptions: PositionOptions; dragBehavior: SorterDragBehaviorOptions; eventHandlers: SorterEventHandlers<NodeType>; } declare class Dimension { top: number; left: number; height: number; width: number; offsets: ReturnType<CanvasModule["getElementOffsets"]>; dir?: boolean; /** * Initializes the DimensionCalculator with the given initial dimensions. * * @param initialDimensions - The initial dimensions containing `top`, `left`, `height`, `width`, and other properties. */ constructor(initialDimensions: { top: number; left: number; height: number; width: number; offsets: ReturnType<CanvasModule["getElementOffsets"]>; dir?: boolean; el?: HTMLElement; indexEl?: number; }); /** * Calculates the difference between the current and previous dimensions. * If there are no previous dimensions, it will return zero differences. * * @returns An object containing the differences in `top` and `left` positions. */ calculateDimensionDifference(dimension: Dimension): { topDifference: number; leftDifference: number; }; /** * Updates the current dimensions by adding the given differences to the `top` and `left` values. * * @param topDifference - The difference to add to the current `top` value. * @param leftDifference - The difference to add to the current `left` value. */ adjustDimensions(difference: { topDifference: number; leftDifference: number; }): Dimension; /** * Determines the placement ('before' or 'after') based on the X and Y coordinates and center points. * * @param {number} mouseX X coordinate of the mouse * @param {number} mouseY Y coordinate of the mouse * @return {Placement} 'before' or 'after' */ determinePlacement(mouseX: number, mouseY: number): Placement; /** * Compares the current dimension object with another dimension to check equality. * * @param {Dimension} dimension - The dimension to compare against. * @returns {boolean} True if the dimensions are equal, otherwise false. */ equals(dimension: Dimension | undefined): boolean; /** * Creates a clone of the current Dimension object. * * @returns {Dimension} A new Dimension object with the same properties. */ clone(): Dimension; getDropArea(config: DroppableZoneConfig): Dimension; private adjustDropDimension; /** * Checks if the given coordinates are within the bounds of this dimension instance. * * @param {number} x - The X coordinate to check. * @param {number} y - The Y coordinate to check. * @returns {boolean} - True if the coordinates are within bounds, otherwise false. */ isWithinBounds(x: number, y: number): boolean; } declare abstract class SortableTreeNode<T> { protected _model: T; protected _dragSource: DragSource<T>; protected _dropAreaConfig: DroppableZoneConfig; /** The dimensions of the node. */ nodeDimensions?: Dimension; /** The dimensions of the child elements within the target node. */ childrenDimensions?: Dimension[]; constructor(model: T, dragSource?: DragSource<T>); /** * Get the list of children of this node. * * @returns {SortableTreeNode<T>[] | null} - List of children or null if no children exist. */ abstract getChildren(): SortableTreeNode<T>[] | null; /** * Get the parent node of this node, or null if it has no parent. * * @returns {SortableTreeNode<T> | null} - Parent node or null if it has no parent. */ abstract getParent(): SortableTreeNode<T> | null; /** * Add a child node at a particular index. * * @param {SortableTreeNode<T>} node - The node to add. * @param {number} index - The position to insert the child node at. * @returns {SortableTreeNode<T>} - The added node. */ abstract addChildAt(node: SortableTreeNode<T>, index: number): SortableTreeNode<T>; /** * Remove a child node at a particular index. * * @param {number} index - The index to remove the child node from. */ abstract removeChildAt(index: number): void; /** * Get the index of a child node in the current node's list of children. * * @param {SortableTreeNode<T>} node - The node whose index is to be found. * @returns {number} - The index of the node, or -1 if the node is not a child. */ abstract indexOfChild(node: SortableTreeNode<T>): number; /** * Determine if a node can be moved to a specific index in another node's children list. * * @param {SortableTreeNode<T>} source - The node to be moved. * @param {number} index - The index at which the node will be inserted. * @returns {boolean} - True if the move is allowed, false otherwise. */ abstract canMove(source: SortableTreeNode<T>, index: number): boolean; /** * Get the view associated with this node, if any. * * @returns {View | undefined} - The view associated with this node, or undefined if none. */ abstract get view(): View | undefined; /** * Get the HTML element associated with this node. * * @returns {HTMLElement} - The associated HTML element. */ abstract get element(): HTMLElement | undefined; /** * Get the model associated with this node. * * @returns {T} - The associated model. */ get model(): T; get dragSource(): DragSource<T>; get dropArea(): Dimension | undefined; /** * Checks if the given coordinates are within the bounds of this node. * * @param {number} x - The X coordinate to check. * @param {number} y - The Y coordinate to check. * @returns {boolean} - True if the coordinates are within bounds, otherwise false. */ isWithinDropBounds(x: number, y: number): boolean; equals(node?: SortableTreeNode<T>): node is SortableTreeNode<T>; adjustDimensions(diff: { topDifference: number; leftDifference: number; }): void; } declare abstract class BaseComponentNode extends SortableTreeNode<Component> { private displayCache; /** * Get the list of child components. * @returns {BaseComponentNode[] | null} - The list of children wrapped in * BaseComponentNode, or null if there are no children. */ getChildren(): BaseComponentNode[] | null; /** * Get the list of displayed children, i.e., components that have a valid HTML element. * Cached values are used to avoid recalculating the display status unnecessarily. * @returns {BaseComponentNode[] | null} - The list of displayed children wrapped in * BaseComponentNode, or null if there are no displayed children. */ private getDisplayedChildren; /** * Check if a child is displayed, using cached value if available. * @param {Component} child - The child component to check. * @returns {boolean} - Whether the child is displayed. */ private isChildDisplayed; /** * Get the parent component of this node. * @returns {BaseComponentNode | null} - The parent wrapped in BaseComponentNode, * or null if no parent exists. */ getParent(): BaseComponentNode | null; /** * Add a child component to this node at the specified index. * @param {BaseComponentNode} node - The child node to add. * @param {number} displayIndex - The visual index at which to insert the child. * @param {{ action: string }} options - Options for the operation, with the default action being 'add-component'. * @returns {BaseComponentNode} - The newly added child node wrapped in BaseComponentNode. */ addChildAt(node: BaseComponentNode, displayIndex: number, options?: { action: string; }): BaseComponentNode; /** * Remove a child component at the specified index. * @param {number} displayIndex - The visual index of the child to remove. * @param {{ temporary: boolean }} options - Whether to temporarily remove the child. */ removeChildAt(displayIndex: number, options?: { temporary: boolean; }): void; /** * Get the visual index of a child node within the displayed children. * @param {BaseComponentNode} node - The child node to locate. * @returns {number} - The index of the child node, or -1 if not found. */ indexOfChild(node: BaseComponentNode): number; /** * Get the index of the given node within the displayed children. * @param {BaseComponentNode} node - The node to find. * @returns {number} - The display index of the node, or -1 if not found. */ private getDisplayIndex; /** * Convert a display index to the actual index within the component's children array. * @param {number} index - The display index to convert. * @returns {number} - The corresponding real index, or -1 if not found. */ getRealIndex(index: number): number; /** * Check if a source node can be moved to a specified index within this component. * @param {BaseComponentNode} source - The source node to move. * @param {number} index - The display index to move the source to. * @returns {boolean} - True if the move is allowed, false otherwise. */ canMove(source: BaseComponentNode, index: number): boolean; /** * Abstract method to get the view associated with this component. * Subclasses must implement this method. * @abstract */ abstract get view(): any; /** * Abstract method to get the DOM element associated with this component. * Subclasses must implement this method. * @abstract */ abstract get element(): HTMLElement | undefined; /** * Reset the state of the node by clearing its status and disabling editing. */ restNodeState(): void; /** * Set the contentEditable property of the node's DOM element. * @param {boolean} value - True to make the content editable, false to disable editing. */ setContentEditable(value: boolean): void; /** * Disable editing capabilities for the component's view. * This method depends on the presence of the `disableEditing` method in the view. */ private disableEditing; /** * Clear the current state of the node by resetting its status. */ private clearState; /** * Set the state of the node to 'selected-parent'. */ setSelectedParentState(): void; /** * Determine if the component is a text node. * @returns {boolean} - True if the component is a text node, false otherwise. */ isTextNode(): boolean; /** * Determine if the component is textable. * @returns {boolean} - True if the component is textable, false otherwise. */ isTextable(): boolean; } declare class CanvasComponentNode extends BaseComponentNode { protected _dropAreaConfig: { ratio: number; minUndroppableDimension: number; maxUndroppableDimension: number; }; /** * Get the associated view of this component. * @returns The view associated with the component, or undefined if none. */ get view(): ComponentView<Component> | undefined; /** * Get the associated element of this component. * @returns The Element associated with the component, or undefined if none. */ get element(): HTMLElement | undefined; } declare class CanvasNewComponentNode extends CanvasComponentNode { canMove(source: CanvasNewComponentNode, index: number): boolean; private canMoveSingleContent; addChildAt(node: CanvasNewComponentNode, index: number): CanvasNewComponentNode; /** * Adds a single content item to the current node. * @param {ContentType} content - The content to add. * @param {number} index - The index where the content is to be added. * @param {boolean} insertingTextableIntoText - Whether the operation involves textable content. * @returns {CanvasNewComponentNode} - The newly added node. */ private addSingleChild; /** * Adds multiple content items as children, looping through the array. * @param {any[]} contentArray - Array of content items * @param {number} index - Index to start adding children * @param {boolean} insertingTextableIntoText - Whether inserting textable content * @returns {CanvasNewComponentNode} The last added node */ private addMultipleChildren; /** * Checks if the source component belongs to the same symbol model as the current component. * @param {Component | undefined} symbolModel - Symbol model to compare * @returns {boolean} Whether the source is the same symbol */ private isSourceSameSymbol; set content(content: ContentType | (() => ContentType)); } export type ContainerContext = { container: HTMLElement; itemSel: string; customTarget?: CustomTarget; document: Document; }; export interface DropLocationDeterminerOptions<T, NodeType extends SortableTreeNode<T>> { em: EditorModel; treeClass: new (model: T, dragSource?: DragSource<T>) => NodeType; containerContext: ContainerContext; positionOptions: PositionOptions; dragDirection: DragDirection; eventHandlers: SorterEventHandlers<NodeType>; } /** * Represents the data related to the last move event during drag-and-drop sorting. * This type is discriminated by the presence or absence of a valid target node. */ export type lastMoveData<NodeType> = { /** The target node under the mouse pointer during the last move. */ targetNode?: NodeType; /** The node under the mouse pointer during this move*/ hoveredNode?: NodeType; /** The index where the placeholder or dragged element should be inserted. */ index?: number; /** Placement relative to the target ('before' or 'after'). */ placement?: Placement; /** The mouse event, used if we want to move placeholder with scrolling. */ mouseEvent?: MouseEvent; placeholderDimensions?: Dimension; }; declare class DropLocationDeterminer<T, NodeType extends SortableTreeNode<T>> extends View { em: EditorModel; treeClass: new (model: any, dragSource?: DragSource<T>) => NodeType; positionOptions: PositionOptions; containerContext: ContainerContext; dragDirection: DragDirection; eventHandlers: SorterEventHandlers<NodeType>; sourceNodes: NodeType[]; lastMoveData: lastMoveData<NodeType>; containerOffset: { top: number; left: number; }; private moveThreshold; private rateLimiter; constructor(options: DropLocationDeterminerOptions<T, NodeType>); /** * Picking components to move * @param {HTMLElement[]} sourceElements * */ startSort(sourceNodes: NodeType[]): void; private bindDragEventHandlers; /** * Triggers the `onMove` event. * * This method is should be called when the user scrolls within the container, using the last recorded mouse event * to determine the new target. */ recalculateTargetOnScroll(): void; private onMove; private handleMove; private adjustForScroll; private restLastMoveData; private triggerLegacyOnMoveCallback; private triggerMoveEvent; /** * Handles the movement of the dragged element over a target node. * Updates the placeholder position and triggers relevant events when necessary. * * @param node - The node currently being hovered over. * @param mouseX - The x-coordinate of the mouse relative to the container. * @param mouseY - The y-coordinate of the mouse relative to the container. */ private getDropPosition; /** * Retrieves the target node based on the mouse event. * Determines the element being hovered, its corresponding model, and * calculates the valid parent node to use as the target node. * * @param mouseEvent - The mouse event containing the cursor position and target element. * @returns The target node if a valid one is found, otherwise undefined. */ private getTargetNode; /** * Creates a new hovered node or reuses the last hovered node if it is the same. * * @param hoveredModel - The model corresponding to the hovered element. * @returns The new or reused hovered node. */ private getOrCreateHoveredNode; /** * Checks if the target node has changed and returns the last one if they are identical. * * @param targetNode - The newly calculated target node. * @returns The new or reused target node. */ private getOrReuseTargetNode; private getMouseTargetElement; private onDragStart; endDrag(): void; cancelDrag(): void; private finalizeMove; private dropDragged; private triggerOnDragEndEvent; /** * Retrieves the first element that has a data model associated with it. * Traverses up the DOM tree from the given element until it reaches the container * or an element with a data model. * * @param mouseTargetEl - The element to start searching from. * @returns The first element with a data model, or null if not found. */ private getFirstElementWithAModel; private getValidParent; private handleParentTraversal; private getIndexInParent; private triggerDragValidation; /** * Clean up event listeners that were attached during the move. * * @param {HTMLElement} container - The container element. * @param {Document[]} docs - List of documents. * @private */ private cleanupEventListeners; /** * Determines if an element is in the normal flow of the document. * This checks whether the element is not floated or positioned in a way that removes it from the flow. * * @param {HTMLElement} el - The element to check. * @param {HTMLElement} [parent=document.body] - The parent element for additional checks (defaults to `document.body`). * @return {boolean} Returns `true` if the element is in flow, otherwise `false`. * @private */ private getDirection; /** * Get children dimensions * @param {NodeType} el Element root * @return {Array} * */ private getChildrenDim; /** * Gets the mouse position relative to the container, adjusting for scroll and canvas relative options. * * @return {{ mouseXRelativeToContainer: number, mouseYRelativeToContainer: number }} - The mouse X and Y positions relative to the container. * @private */ private getMousePositionRelativeToContainer; /** * Caches the container position and updates relevant variables for position calculation. * * @private */ private cacheContainerPosition; /** * Returns dimensions and positions about the element * @param {HTMLElement} el * @return {Dimension} */ private getDim; } declare class PlaceholderClass extends View { pfx: string; allowNesting: boolean; container: HTMLElement; el: HTMLElement; offset: { top: number; left: number; }; private moveLimiter; constructor(options: { container: HTMLElement; pfx?: string; allowNesting?: boolean; el: HTMLElement; offset: { top: number; left: number; }; }); show(): void; hide(): void; /** * Updates the position of the placeholder with a movement threshold. * @param {Dimension} elementDimension element dimensions. * @param {Placement} placement either before or after the target. */ move(elementDimension: Dimension, placement: Placement): void; private _move; /** * Sets the orientation of the placeholder based on the element dimensions. * @param {Dimension} elementDimension Dimensions of the element at the index. */ private setOrientationForDimension; /** * Sets the placeholder's class to vertical. */ private setOrientation; /** * Updates the CSS styles of the placeholder element. * @param {number} top Top position of the placeholder. * @param {number} left Left position of the placeholder. * @param {string} width Width of the placeholder. * @param {string} height Height of the placeholder. */ private updateStyles; private adjustOffset; } declare class Sorter<T, NodeType extends SortableTreeNode<T>> { em: EditorModel; treeClass: new (model: T, dragSource?: DragSource<T>) => NodeType; placeholder: PlaceholderClass; dropLocationDeterminer: DropLocationDeterminer<T, NodeType>; positionOptions: PositionOptions; containerContext: SorterContainerContext; dragBehavior: SorterDragBehaviorOptions; eventHandlers: SorterEventHandlers<NodeType>; sourceNodes?: NodeType[]; constructor(sorterOptions: SorterOptions<T, NodeType>); /** * Picking components to move * @param {HTMLElement[]} sources[] * */ startSort(sources: { element?: HTMLElement; dragSource?: DragSource<T>; }[]): void; validTarget(targetEl: HTMLElement | undefined, sources: { element?: HTMLElement; dragSource?: DragSource<T>; }[], index: number): boolean; private getSourceNodes; /** * This method is should be called when the user scrolls within the container. */ protected recalculateTargetOnScroll(): void; /** * Called when the drag operation should be cancelled */ cancelDrag(): void; /** * Called to drop an item onto a valid target. */ endDrag(): void; private handlePlaceholderMove; /** * Creates a new placeholder element for the drag-and-drop operation. * * @returns {PlaceholderClass} The newly created placeholder instance. */ private createPlaceholder; private ensurePlaceholderElement; /** * Triggered when the offset of the editor is changed */ private updateOffset; /** * Finds the closest valid source element within the container context. * @param sourceElement - The initial source element to check. * @returns The closest valid source element, or null if none is found. */ private findValidSourceElement; protected bindDragEventHandlers(): void; private updatePlaceholderPosition; /** * Clean up event listeners that were attached during the move. * * @private */ protected cleanupEventListeners(): void; /** * Finalize the move. * * @private */ protected finalizeMove(): void; /** * Cancels the drag on Escape press ( nothing is dropped or moved ) * @param {KeyboardEvent} e - The keyboard event object. */ private rollback; protected triggerNullOnEndMove(dragIsCancelled: boolean): void; } export interface CategoryViewConfig { em: EditorModel; pStylePrefix?: string; stylePrefix?: string; } declare class CategoryView extends View<Category> { em: EditorModel; config: CategoryViewConfig; pfx: string; caretR: string; caretD: string; iconClass: string; activeClass: string; iconEl?: HTMLElement; typeEl?: HTMLElement; catName: string; events(): { "click [data-title]": string; }; template({ pfx, label, catName }: { pfx: string; label: string; catName: string; }): string; /** @ts-ignore */ attributes(): Record<string, any>; constructor(o: any, config: CategoryViewConfig, catName: string); updateVisibility(): void; open(): void; close(): void; toggle(): void; getIconEl(): HTMLElement; getTypeEl(): HTMLElement; append(el: HTMLElement): void; render(): this; } interface CategoryProperties { /** * Category id. */ id: string; /** * Category label. */ label: string; /** * Category open state. * @default true */ open?: boolean; /** * Category order. */ order?: string | number; /** * Category attributes. * @default {} */ attributes?: Record<string, any>; } export interface ItemsByCategory<T> { category?: Category; items: T[]; } export declare class Category extends Model<CategoryProperties> { view?: CategoryView; defaults(): { id: string; label: string; open: boolean; attributes: {}; }; getId(): string; getLabel(): string; } export type CategoryCollectionParams = ConstructorParameters<typeof Collection<Category>>; export interface CategoryOptions { events?: { update?: string; }; em?: EditorModel; } export declare class Categories extends Collection<Category> { constructor(models?: CategoryCollectionParams[0], opts?: CategoryOptions); /** @ts-ignore */ add(model: (CategoryProperties | Category)[] | CategoryProperties | Category, opts?: AddOptions): Category; get(id: string | Category): Category; } export interface ModelWithCategoryProps { category?: string | CategoryProperties; } declare abstract class CollectionWithCategories<T extends Model<ModelWithCategoryProps>> extends Collection<T> { abstract getCategories(): Categories; initCategory(model: T): Category | undefined; } export declare class Blocks extends CollectionWithCategories<Block> { em: EditorModel; constructor(coll: any[], options: { em: EditorModel; }); getCategories(): Categories; handleAdd(model: Block): void; } /** @private */ export interface BlockProperties extends DraggableContent { /** * Block label, eg. `My block` */ label: string; /** * HTML string for the media/icon of the block, eg. `<svg ...`, `<img ...`, etc. * @default '' */ media?: string; /** * Block category, eg. `Basic blocks` * @default '' */ category?: string | CategoryProperties; /** * If true, triggers the `active` event on the dropped component. * @default false */ activate?: boolean; /** * If true, the dropped component will be selected. * @default false */ select?: boolean; /** * If true, all IDs of dropped components and their styles will be changed. * @default false */ resetId?: boolean; /** * Disable the block from being interacted. * @default false */ disable?: boolean; /** * Custom behavior on click. * @example * onClick: (block, editor) => editor.getWrapper().append(block.get('content')) */ onClick?: (block: Block, editor: Editor) => void; /** * Block attributes */ attributes?: Record<string, any>; id?: string; /** * @deprecated */ activeOnRender?: boolean; } /** * @property {String} label Block label, eg. `My block` * @property {String|Object} content The content of the block. Might be an HTML string or a [Component Defintion](/modules/Components.html#component-definition) * @property {String} [media=''] HTML string for the media/icon of the block, eg. `<svg ...`, `<img ...`, etc. * @property {String} [category=''] Block category, eg. `Basic blocks` * @property {Boolean} [activate=false] If true, triggers the `active` event on the dropped component. * @property {Boolean} [select=false] If true, the dropped component will be selected. * @property {Boolean} [resetId=false] If true, all IDs of dropped components and their styles will be changed. * @property {Boolean} [disable=false] Disable the block from being interacted * @property {Function} [onClick] Custom behavior on click, eg. `(block, editor) => editor.getWrapper().append(block.get('content'))` * @property {Object} [attributes={}] Block attributes to apply in the view element * * @module docsjs.Block */ export declare class Block extends Model<BlockProperties> { defaults(): { label: string; content: string; media: string; category: string; activate: boolean; select: undefined; resetId: boolean; disable: boolean; onClick: undefined; attributes: {}; dragDef: {}; }; get category(): Category | undefined; get parent(): Blocks; /** * Get block id * @returns {String} */ getId(): string; /** * Get block label * @returns {String} */ getLabel(): string; /** * Get block media * @returns {String} */ getMedia(): string | undefined; /** * Get block content * @returns {Object|String|Array<Object|String>} */ getContent(): ContentType | (() => ContentType) | undefined; /** * Get block component dragDef * @returns {ComponentDefinition} */ getDragDef(): ComponentDefinition | undefined; /** * Get block category label * @returns {String} */ getCategoryLabel(): string; } declare class ComponentSorter<NodeType extends BaseComponentNode> extends Sorter<Component, NodeType> { targetIsText: boolean; __currentBlock?: Block; constructor({ em, treeClass, containerContext, dragBehavior, positionOptions, eventHandlers, }: { em: EditorModel; treeClass: new (model: Component, dragSource?: DragSource<Component>) => NodeType; containerContext: SorterContainerContext; dragBehavior: SorterDragBehaviorOptions; positionOptions?: PositionOptions; eventHandlers?: SorterEventHandlers<NodeType>; }); private onStartSort; protected bindDragEventHandlers(): void; protected cleanupEventListeners(): void; handleScrollEvent(...agrs: any[]): void; private onMouseMove; /** * Handles the drop action by moving the source nodes to the target node. * Calls appropriate handlers based on whether the move was successful or not. * * @param targetNode - The node where the source nodes will be dropped. * @param sourceNodes - The nodes being dropped. * @param index - The index at which to drop the source nodes. */ private onDrop; /** * Handles the addition of multiple source nodes to the target node. * If the move is valid, adds the nodes at the specified index and increments the index. * * @param targetNode - The target node where source nodes will be added. * @param sourceNodes - The nodes being added. * @param index - The initial index at which to add the source nodes. * @returns The list of successfully added nodes. */ private handleNodeAddition; /** * Determines if a source node position has changed. * * @param targetNode - The node where the source node will be moved. * @param sourceNode - The node being moved. * @param index - The index at which to move the source node. * @returns Whether the node can be moved. */ private isPositionChanged; /** * Moves a source node to the target node at the specified index, handling edge cases. * * @param targetNode - The node where the source node will be moved. * @param sourceNode - The node being moved. * @param index - The index at which to move the source node. * @returns An object containing the added node and its new index, or null if it couldn't be moved. */ private moveNode; /** * Triggers the end move event for a node that was added to the target. * * @param addedNode - The node that was moved and added to the target. */ private triggerEndMoveEvent; /** * Finalize the move by removing any helpers and selecting the target model. * * @private */ protected finalizeMove(): void; private onTargetChange; private updateTextViewCursorPosition; /** * Change Autoscroll while sorting * @param {Boolean} active */ private setAutoCanvasScroll; } export type DragStop = (cancel?: boolean) => void; declare class Droppable { em: EditorModel; canvas: CanvasModule; el: HTMLElement; counter: number; getSorterOptions?: (sorter: any) => Record<string, any> | null; over?: boolean; dragStop?: DragStop; draggedNode?: CanvasNewComponentNode; sorter: ComponentSorter<CanvasNewComponentNode>; setAbsoluteDragContent?: (cnt: any) => any; constructor(em: EditorModel, rootEl?: HTMLElement); toggleEffects(el: HTMLElement, enable: boolean): void; __customTglEff(enable: boolean): void; startCustom(): void; endCustom(cancel?: boolean): void; /** * This function is expected to be always executed at the end of d&d. */ endDrop(cancel?: boolean, ev?: Event): void; handleDragLeave(ev: Event): void; updateCounter(value: number, ev: Event): void; handleDragEnter(ev: DragEvent | Event): void; /** * Generates a temporary model of the content being dragged for use with the sorter. * @returns The temporary model representing the dragged content. */ private getTempDropModel; handleDragEnd(model: any, dt: any): void; /** * Always need to have this handler active for enabling the drop * @param {Event} ev */ handleDragOver(ev: Event): void; /** * WARNING: This function might fail to run on drop, for example, when the * drop, accidentally, happens on some external element (DOM not inside the iframe) */ handleDrop(ev: Event | DragEvent): void; getContentByData(dt: any): { content: any; }; } export interface PageManagerConfig extends ModuleConfig { /** * Default pages. */ pages?: PageProperties[]; /** * ID of the page to select on editor load. */ selected?: string; } export interface SelectableOption { /** * Select the page. */ select?: boolean; } export interface AbortOption { abort?: boolean; } declare enum PagesEvents { /** * @event `page:add` Added new page. The page is passed as an argument to the callback. * @example * editor.on('page:add', (page) => { ... }); */ add = "page:add", addBefore = "page:add:before", /** * @event `page:remove` Page removed. The page is passed as an argument to the callback. * @example * editor.on('page:remove', (page) => { ... }); */ remove = "page:remove", removeBefore = "page:remove:before", /** * @event `page:select` New page selected. The newly selected page and the previous one, are passed as arguments to the callback. * @example * editor.on('page:select', (page, previousPage) => { ... }); */ select = "page:select", selectBefore = "page:select:before", /** * @event `page:update` Page updated. The updated page and the object containing changes are passed as arguments to the callback. * @example * editor.on('page:update', (page, changes) => { ... }); */ update = "page:update", /** * @event `page` Catch-all event for all the events mentioned above. An object containing all the available data about the triggered event is passed as an argument to the callback. * @example * editor.on('page', ({ event, model, ... }) => { ... }); */ all = "page" } export declare class Frames extends ModuleCollection<Frame> { loadedItems: number; itemsToLoad: number; page?: Page; constructor(module: CanvasModule, models?: Frame[] | Array<Record<string, any>>); onAdd(frame: Frame): void; onReset(m: Frame, opts?: { previousModels?: Frame[]; }): void; onRemove(frame: Frame): void; initRefs(): void; itemLoaded(): void; listenToLoad(): void; listenToLoadItems(on: boolean): void; } /** @private */ export interface PageProperties { /** * Panel id. */ id?: string; /** * Page name. */ name?: string; /** * HTML to load as page content. */ component?: string | ComponentDefinition | ComponentDefinition[]; /** * CSS to load with the page. */ styles?: string | CssRuleJSON[]; [key: string]: unknown; } export interface PagePropertiesDefined extends Pick<PageProperties, "id" | "name"> { frames: Frames; [key: string]: unknown; } export declare class Page extends Model<PagePropertiesDefined> { defaults(): { name: string; frames: Frames; _undo: boolean; }; em: EditorModel; constructor(props: any, opts?: { em?: EditorModel; config?: PageManagerConfig; }); onRemove(): void; getFrames(): Frames; /** * Get page id * @returns {String} */ getId(): string; /** * Get page name * @returns {String} */ getName(): string; /** * Update page name * @param {String} name New page name * @example * page.setName('New name'); */ setName(name: string): this; /** * Get all frames * @returns {Array<Frame>} * @example * const arrayOfFrames = page.getAllFrames(); */ getAllFrames(): Frame[]; /** * Get the first frame of the page (identified always as the main one) * @returns {Frame} * @example * const mainFrame = page.getMainFrame(); */ getMainFrame(): Frame; /** * Get the root component (usually is the `wrapper` component) from the main frame * @returns {Component} * @example * const rootComponent = page.getMainComponent(); * console.log(rootComponent.toHTML()); */ getMainComponent(): ComponentWrapper; toJSON(opts?: {}): any; } export declare class Canvas extends ModuleModel<CanvasModule> { defaults(): { frame: string; frames: never[]; rulers: boolean; zoom: number; x: number; y: number; scripts: never[]; styles: never[]; pointer: Coordinates; pointerScreen: Coordinates; }; constructor(module: CanvasModule); get frames(): Frames; init(): void; _pageUpdated(page: Page, prev?: Page): void; updateDevice(opts?: any): void; onZoomChange(): void; onCoordsChange(): void; onPointerChange(): void; getPointerCoords(type?: CoordinatesTypes): Coordinates; } export type DraggerPosition = Position & { end?: boolean; }; export type Guide = { x: number; y: number; lock?: number; active?: boolean; }; export interface DraggerOptions { /** * Element on which the drag will be executed. By default, the document will be used */ container?: HTMLElement; /** * Callback on drag start. * @example * onStart(ev, dragger) { * console.log('pointer start', dragger.startPointer, 'position start', dragger.startPosition); * } */ onStart?: (ev: Event, dragger: Dragger) => void; /** * Callback on drag. * @example * onDrag(ev, dragger) { * console.log('pointer', dragger.currentPointer, 'position', dragger.position, 'delta', dragger.delta); * } */ onDrag?: (ev: Event, dragger: Dragger) => void; /** * Callback on drag end. * @example * onEnd(ev, dragger) { * console.log('pointer', dragger.currentPointer, 'position', dragger.position, 'delta', dragger.delta); * } */ onEnd?: (ev: Event, dragger: Dragger, opts: { cancelled: boolean; }) => void; /** * Indicate a callback where to pass an object with new coordinates */ setPosition?: (position: DraggerPosition) => void; /** * Indicate a callback where to get initial coordinates. * @example * getPosition: () => { * // ... * return { x: 10, y: 100 } * } */ getPosition?: () => DraggerPosition; /** * Indicate a callback where to get pointer coordinates. */ getPointerPosition?: (ev: Event) => DraggerPosition; /** * Static guides to be snapped. */ guidesStatic?: () => Guide[]; /** * Target guides that will snap to static one. */ guidesTarget?: () => Guide[]; /** * Offset before snap to guides. * @default 5 */ snapOffset?: number; /** * Document on which listen to pointer events. */ doc?: Document; /** * Scale result points, can also be a function. * @default 1 */ scale?: number | (() => number); } declare class Dragger { opts: DraggerOptions; startPointer: DraggerPosition; delta: DraggerPosition; lastScroll: DraggerPosition; lastScrollDiff: DraggerPosition; startPosition: DraggerPosition; globScrollDiff: DraggerPosition; currentPointer: DraggerPosition; position: DraggerPosition; el?: HTMLElement; guidesStatic: Guide[]; guidesTarget: Guide[]; lockedAxis?: any; docs: Document[]; trgX?: Guide; trgY?: Guide; /** * Init the dragger * @param {Object} opts */ constructor(opts?: DraggerOptions); /** * Update options * @param {Object} options */ setOptions(opts?: Partial<DraggerOptions>): void; toggleDrag(enable?: boolean): void; handleScroll(): void; /** * Start dragging * @param {Event} e */ start(ev: Event): void; /** * Drag event * @param {Event} event */ drag(ev: Event): void; /** * Check if the delta hits some guide */ snapGuides(delta: DraggerPosition): { newDelta: DraggerPosition; trgX: Guide | undefined; trgY: Guide | undefined; }; isPointIn(src: number, trg: number, { offset }?: { offset?: number; }): boolean; setGuideLock(guide: Guide, value: any): Guide; /** * Stop dragging */ stop(ev: Event, opts?: { cancel?: boolean; }): void; keyHandle(ev: Event): void; /** * Move the element * @param {integer} x * @param {integer} y */ move(x: number, y: number, end?: boolean): void; getContainerEl(): Document[] | HTMLElement[]; getWindowEl(): any[]; /** * Returns documents */ getDocumentEl(el?: HTMLElement): Document[]; /** * Get mouse coordinates * @param {Event} event * @return {Object} */ getPointerPos(ev: Event): DraggerPosition; getStartPosition(): { x: number; y: number; }; getScrollInfo(): { y: number; x: number; }; detectAxisLock(x: number, y: number): "x" | "y" | undefined; } export interface ToScreenOption { toScreen?: boolean; } export interface ToWorldOption { toWorld?: boolean; } export interface GetBoxRectOptions extends ToScreenOption { local?: boolean; } export interface CanvasRefreshOptions { /** * Refresh canvas spots. */ spots?: boolean; all?: boolean; } declare enum CanvasEvents { /** * @event `canvas:dragenter` Something is dragged inside the canvas, `DataTransfer` instance passed as an argument. */ dragEnter = "canvas:dragenter", /** * @event `canvas:dragover` Something is dragging on the canvas, `DataTransfer` instance passed as an argument. */ dragOver = "canvas:dragover", /** * @event `canvas:dragend` When a drag operation is ended, `DataTransfer` instance passed as an argument. */ dragEnd = "canvas:dragend", /** * @event `canvas:dragdata` On any dataTransfer parse, `DataTransfer` instance and the `result` are passed as arguments. By changing `result.content` you're able to customize what is dropped. */ dragData = "canvas:dragdata", /** * @event `canvas:drop` Something is dropped in canvas, `DataTransfer` instance and the dropped model are passed as arguments. */ drop = "canvas:drop", /** * @event `canvas:spot` Spots updated. * @example * editor.on('canvas:spot', () => { * console.log('Spots', editor.Canvas.getSpots()); * }); */ spot = "canvas:spot", /** * @event `canvas:spot:add` New canvas spot added. * @example * editor.on('canvas:spot:add', ({ spot }) => { * console.log('Spot added', spot); * }); */ spotAdd = "canvas:spot:add", /** * @event `canvas:spot:update` Canvas spot updated. * @example * editor.on('canvas:spot:update', ({ spot }) => { * console.log('Spot updated', spot); * }); */ spotUpdate = "canvas:spot:update", /** * @event `canvas:spot:remove` Canvas spot removed. * @example * editor.on('canvas:spot:remove', ({ spot }) => { * console.log('Spot removed', spot); * }); */ spotRemove = "canvas:spot:remove", /** * @event `canvas:coords` Canvas coordinates updated. * @example * editor.on('canvas:coords', () => { * console.log('Canvas coordinates updated:', editor.Canvas.getCoords()); * }); */ coords = "canvas:coords", /** * @event `canvas:zoom` Canvas zoom updated. * @example * editor.on('canvas:zoom', () => { * console.log('Canvas zoom updated:', editor.Canvas.getZoom()); * }); */ zoom = "canvas:zoom", /** * @event `canvas:pointer` Canvas pointer updated. * @example * editor.on('canvas:pointer', () => { * console.log('Canvas pointer updated:', editor.Canvas.getPointer()); * }); */ pointer = "canvas:pointer", /** * @event `canvas:refresh` Canvas was refreshed to update elements on top, like spots/tools (eg. via `editor.Canvas.refresh()` or on frame resize). * @example * editor.on('canvas:refresh', (canvasRefreshOptions) => { * console.log('Canvas refreshed with options:', canvasRefreshOptions); * }); */ refresh = "canvas:refresh", /** * @event `canvas:frame:load` Frame loaded in canvas. The event is triggered right after iframe's `onload`. * @example * editor.on('canvas:frame:load', ({ window }) => { * console.log('Frame loaded', window); * }); */ frameLoad = "canvas:frame:load", /** * @event `canvas:frame:load:head` Frame head loaded in canvas. The event is triggered right after iframe's finished to load the head elemenets (eg. scripts) * @example * editor.on('canvas:frame:load:head', ({ window }) => { * console.log('Frame head loaded', window); * }); */ frameLoadHead = "canvas:frame:load:head", /** * @event `canvas:frame:load:body` Frame body loaded in canvas. The event is triggered when the body i