UNPKG

grapesjs

Version:

Free and Open Source Web Builder Framework

1,485 lines (1,483 loc) 429 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 const DataCollectionVariableType = "data-collection-variable"; declare const DataVariableType: "data-variable"; export interface DataVariableProps { type: typeof DataVariableType; path: string; defaultValue?: string; } declare class DataVariable extends Model<DataVariableProps> { em?: EditorModel; defaults(): { type: "data-variable"; defaultValue: string; path: string; }; constructor(props: DataVariableProps, options: { em?: EditorModel; }); getDataValue(): any; } declare enum DataCollectionStateVariableType { currentIndex = "currentIndex", startIndex = "startIndex", currentItem = "currentItem", endIndex = "endIndex", collectionId = "collectionId", totalItems = "totalItems", remainingItems = "remainingItems" } export interface DataCollectionState { [DataCollectionStateVariableType.currentIndex]: number; [DataCollectionStateVariableType.startIndex]: number; [DataCollectionStateVariableType.currentItem]: DataVariableProps; [DataCollectionStateVariableType.endIndex]: number; [DataCollectionStateVariableType.collectionId]: string; [DataCollectionStateVariableType.totalItems]: number; [DataCollectionStateVariableType.remainingItems]: number; } export interface DataCollectionStateMap { [key: string]: DataCollectionState; } export interface DataCollectionVariableProps { type: typeof DataCollectionVariableType; variableType: DataCollectionStateVariableType; collectionId: string; path?: string; } export interface DataResolverListenerProps { em: EditorModel; resolver: DataResolver; onUpdate: (value: any) => void; } declare class DataResolverListener { private listeners; private em; private onUpdate; private model; resolver: DataResolver; constructor(props: DataResolverListenerProps); private onChange; private createListener; listenToResolver(): void; private listenToConditionalVariable; private listenToDataVariable; private listenToDataCollectionVariable; private removeListeners; destroy(): void; } export interface DataCollectionVariablePropsDefined extends DataCollectionVariableProps { value?: any; } declare class DataCollectionVariable extends Model<DataCollectionVariablePropsDefined> { em: EditorModel; collectionsStateMap?: DataCollectionStateMap; dataVariable?: DataVariable; resolverListener?: DataResolverListener; defaults(): Partial<DataCollectionVariablePropsDefined>; constructor(props: DataCollectionVariablePropsDefined, options: { em: EditorModel; collectionsStateMap?: DataCollectionStateMap; }); hasDynamicValue(): boolean; getDataValue(): any; private updateDataVariable; updateCollectionsStateMap(collectionsStateMap: DataCollectionStateMap): void; destroy(): false | JQueryXHR; toJSON(options?: any): any; } export interface DataSourceOptions extends CombinedModelConstructorOptions<{ em: EditorModel; }, DataSource> { } export declare class DataSource<DRProps extends DataRecordProps = DataRecordProps> extends Model<DataSourceType<DRProps>> { transformers: DataSourceTransformers; /** * Returns the default properties for the data source. * These include an empty array of records and an empty object of transformers. * * @returns {Object} The default attributes for the data source. * @name defaults */ defaults(): DataSourceType<DRProps>; /** * Initializes a new instance of the `DataSource` class. * It sets up the transformers and initializes the collection of records. * If the `records` property is not an instance of `DataRecords`, it will be converted into one. * * @param {DataSourceProps<DRProps>} props - Properties to initialize the data source. * @param {DataSourceOptions} opts - Options to initialize the data source. * @name constructor */ constructor(props: DataSourceProps<DRProps>, opts: DataSourceOptions); /** * Retrieves the collection of records associated with this data source. * * @returns {DataRecords<DRProps>} The collection of data records. * @name records */ get records(): NonNullable<DataRecords<DRProps>>; /** * Retrieves the editor model associated with this data source. * * @returns {EditorModel} The editor model. * @name em */ get em(): EditorModel; /** * Handles the `add` event for records in the data source. * This method triggers a change event on the newly added record. * * @param {DataRecord<DRProps>} dr - The data record that was added. * @private * @name onAdd */ onAdd(dr: DataRecord<DRProps>): void; /** * Adds a new record to the data source. * * @param {DRProps} record - The properties of the record to add. * @param {AddOptions} [opts] - Options to apply when adding the record. * @returns {DataRecord} The added data record. * @name addRecord */ addRecord(record: DRProps, opts?: AddOptions): DataRecord<DRProps>; /** * Retrieves a record from the data source by its ID. * * @param {string | number} id - The ID of the record to retrieve. * @returns {DataRecord<DRProps> | undefined} The data record, or `undefined` if no record is found with the given ID. * @name getRecord */ getRecord(id: string | number): DataRecord | undefined; /** * Retrieves all records from the data source. * Each record is processed with the `getRecord` method to apply any read transformers. * * @returns {Array<DataRecord<DRProps> | undefined>} An array of data records. * @name getRecords */ getRecords(): DataRecord<DataRecordProps>[]; /** * Removes a record from the data source by its ID. * * @param {string | number} id - The ID of the record to remove. * @param {RemoveOptions} [opts] - Options to apply when removing the record. * @returns {DataRecord<DRProps> | undefined} The removed data record, or `undefined` if no record is found with the given ID. * @name removeRecord */ removeRecord(id: string | number, opts?: RemoveOptions): DataRecord<DRProps>; /** * Replaces the existing records in the data source with a new set of records. * * @param {Array<DRProps>} records - An array of data record properties to set. * @returns {Array<DataRecord>} An array of the added data records. * @name setRecords */ setRecords(records: DRProps[]): void; private handleChanges; } export declare class DataRecords<T extends DataRecordProps = DataRecordProps> extends Collection<DataRecord<T>> { dataSource: DataSource; constructor(models: DataRecord[] | DataRecordProps[], options: { dataSource: DataSource; }); } export declare class DataRecord<T extends DataRecordProps = DataRecordProps> extends Model<T> { mutable: boolean; constructor(props: T, opts?: {}); get cl(): DataRecords; get dataSource(): DataSource; get em(): EditorModel; get index(): number; /** * Handles changes to the record's attributes. * This method triggers a change event for each property that has been altered. * * @private * @name handleChange */ handleChange(): void; /** * Get the path of the record. * The path is a string that represents the location of the record within the data source. * Optionally, include a property name to create a more specific path. * * @param {String} [prop] - Optional property name to include in the path. * @param {Object} [opts] - Options for path generation. * @param {Boolean} [opts.useIndex] - Whether to use the index of the record in the path. * @returns {String} - The path of the record. * @name getPath * @example * const pathRecord = record.getPath(); * // e.g., 'SOURCE_ID.record1' * const pathRecord2 = record.getPath('myProp'); * // e.g., 'SOURCE_ID.record1.myProp' */ getPath(prop?: string, opts?: { useIndex?: boolean; }): string; /** * Get both ID-based and index-based paths of the record. * Returns an array containing the paths using both ID and index. * * @param {String} [prop] - Optional property name to include in the paths. * @returns {Array<String>} - An array of paths. * @name getPaths * @example * const paths = record.getPaths(); * // e.g., ['SOURCE_ID.record1', 'SOURCE_ID.0'] */ getPaths(prop?: string): string[]; /** * Trigger a change event for the record. * Optionally, include a property name to trigger a change event for a specific property. * * @param {String} [prop] - Optional property name to trigger a change event for a specific property. * @name triggerChange */ triggerChange(prop?: string): void; /** * Set a property on the record, optionally using transformers. * If transformers are defined for the record, they will be applied to the value before setting it. * * @param {String|Object} attributeName - The name of the attribute to set, or an object of key-value pairs. * @param {any} [value] - The value to set for the attribute. * @param {Object} [options] - Options to apply when setting the attribute. * @param {Boolean} [options.avoidTransformers] - If true, transformers will not be applied. * @returns {DataRecord} - The instance of the DataRecord. * @name set * @example * record.set('name', 'newValue'); * // Sets 'name' property to 'newValue' */ set<A extends _StringKey<T>>(attributeName: DeepPartialDot<T> | A, value?: SetOptions | T[A] | undefined, options?: SetOptions | undefined): this; } export type ConditionProps = ExpressionProps | LogicGroupProps | boolean; export interface DataConditionEvaluatorProps { condition: ConditionProps; } declare class DataConditionEvaluator extends Model<DataConditionEvaluatorProps> { private em; constructor(props: DataConditionEvaluatorProps, opts: { em: EditorModel; }); evaluate(): boolean; /** * Factory method for creating operators based on the data type. */ private getOperator; getDependentDataVariables(): DataVariableProps[]; private extractDataVariables; private isLogicGroup; private isExpression; private isOperatorInEnum; toJSON(options?: any): any; } declare enum BooleanOperation { and = "and", or = "or", xor = "xor" } declare enum NumberOperation { greaterThan = ">", lessThan = "<", greaterThanOrEqual = ">=", lessThanOrEqual = "<=", equals = "=", notEquals = "!=" } declare enum StringOperation { contains = "contains", startsWith = "startsWith", endsWith = "endsWith", matchesRegex = "matchesRegex", equalsIgnoreCase = "equalsIgnoreCase", trimEquals = "trimEquals" } declare enum AnyTypeOperation { equals = "equals", isTruthy = "isTruthy", isFalsy = "isFalsy", isDefined = "isDefined", isNull = "isNull", isUndefined = "isUndefined", isArray = "isArray", isObject = "isObject", isString = "isString", isNumber = "isNumber", isBoolean = "isBoolean", isDefaultValue = "isDefaultValue" } declare const DataConditionType = "data-condition"; export interface ExpressionProps { left: any; operator: AnyTypeOperation | StringOperation | NumberOperation; right: any; } export interface LogicGroupProps { logicalOperator: BooleanOperation; statements: ConditionProps[]; } export interface DataConditionProps { type: typeof DataConditionType; condition: ConditionProps; ifTrue: any; ifFalse: any; } export interface DataConditionPropsDefined extends Omit<DataConditionProps, "condition"> { condition: DataConditionEvaluator; } declare class DataCondition extends Model<DataConditionPropsDefined> { private em; private resolverListeners; private _onValueChange?; constructor(props: { condition: ConditionProps; ifTrue: any; ifFalse: any; }, opts: { em: EditorModel; onValueChange?: () => void; }); private get conditionEvaluator(); getCondition(): ConditionProps; getIfTrue(): any; getIfFalse(): any; isTrue(): boolean; getDataValue(skipDynamicValueResolution?: boolean): any; set onValueChange(newFunction: () => void); setCondition(newCondition: ConditionProps): void; setIfTrue(newIfTrue: any): void; setIfFalse(newIfFalse: any): void; private listenToDataVariables; getDependentDataVariables(): DataVariableProps[]; private cleanupListeners; toJSON(): { type: string; condition: DataConditionEvaluator; ifTrue: any; ifFalse: any; }; } export type DataResolver = DataVariable | DataCondition | DataCollectionVariable; export interface DataRecordProps extends ObjectAny { /** * Record id. */ id: string; /** * Specifies if the record is mutable. Defaults to `true`. */ mutable?: boolean; [key: string]: any; } export interface BaseDataSource { /** * DataSource id. */ id: string; /** * DataSource validation and transformation factories. */ transformers?: DataSourceTransformers; /** * If true will store the data source in the GrapesJS project.json file. */ skipFromStorage?: boolean; } export interface DataSourceType<DR extends DataRecordProps> extends BaseDataSource { records: DataRecords<DR>; } export interface DataSourceProps<DR extends DataRecordProps> extends BaseDataSource { records?: DataRecords<DR> | DataRecord<DR>[] | DR[]; } export interface DataSourceTransformers { onRecordSetValue?: (args: { id: string | number; key: string; value: any; }) => any; } declare enum DataSourcesEvents { /** * @event `data:add` Added new data source. * @example * editor.on('data:add', (dataSource) => { ... }); */ add = "data:add", addBefore = "data:add:before", /** * @event `data:remove` Data source removed. * @example * editor.on('data:remove', (dataSource) => { ... }); */ remove = "data:remove", removeBefore = "data:remove:before", /** * @event `data:update` Data source updated. * @example * editor.on('data:update', (dataSource, changes) => { ... }); */ update = "data:update", /** * @event `data:path` Data record path update. * @example * editor.on('data:path:SOURCE_ID:RECORD_ID:PROP_NAME', ({ dataSource, dataRecord, path }) => { ... }); */ path = "data:path", /** * @event `data` Catch-all event for all the events mentioned above. * @example * editor.on('data', ({ event, model, ... }) => { ... }); */ all = "data" } /**{END_EVENTS}*/ export type DotSeparatedKeys<T> = T extends object ? { [K in keyof T]: K extends string ? T[K] extends object ? `${K}` | `${K}.${DotSeparatedKeys<T[K]>}` : `${K}` : never; }[keyof T] : never; export type DeepPartialDot<T> = { [P in DotSeparatedKeys<T>]?: P extends `${infer K}.${infer Rest}` ? K extends keyof T ? Rest extends DotSeparatedKeys<T[K]> ? DeepPartialDot<T[K]>[Rest] : never : never : P extends keyof T ? T[P] : never; }; export interface DynamicWatchersOptions { skipWatcherUpdates?: boolean; fromDataSource?: boolean; } export interface ComponentResolverWatcherOptions { em: EditorModel; collectionsStateMap?: DataCollectionStateMap; } 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 Definition](/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 bein