@tiptap/core 3.12.1 → 3.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -3761,6 +3761,10 @@ type ResizableNodeViewOptions = {
3761
3761
  * The ProseMirror node instance
3762
3762
  */
3763
3763
  node: Node$1;
3764
+ /**
3765
+ * The Tiptap editor instance
3766
+ */
3767
+ editor: Editor;
3764
3768
  /**
3765
3769
  * Function that returns the current position of the node in the document
3766
3770
  */
@@ -3884,6 +3888,50 @@ type ResizableNodeViewOptions = {
3884
3888
  /** Class added to container while actively resizing */
3885
3889
  resizing?: string;
3886
3890
  };
3891
+ /**
3892
+ * Optional callback for creating custom resize handle elements.
3893
+ *
3894
+ * This function allows developers to define their own handle element
3895
+ * (e.g., custom icons, classes, or styles) for a given resize direction.
3896
+ * It is called internally for each handle direction.
3897
+ *
3898
+ * @param direction - The direction of the handle being created (e.g., 'top', 'bottom-right').
3899
+ * @returns The custom handle HTMLElement.
3900
+ *
3901
+ * @example
3902
+ * ```ts
3903
+ * createCustomHandle: (direction) => {
3904
+ * const handle = document.createElement('div')
3905
+ * handle.dataset.resizeHandle = direction
3906
+ * handle.style.position = 'absolute'
3907
+ * handle.className = 'tiptap-custom-handle'
3908
+ *
3909
+ * const isTop = direction.includes('top')
3910
+ * const isBottom = direction.includes('bottom')
3911
+ * const isLeft = direction.includes('left')
3912
+ * const isRight = direction.includes('right')
3913
+ *
3914
+ * if (isTop) handle.style.top = '0'
3915
+ * if (isBottom) handle.style.bottom = '0'
3916
+ * if (isLeft) handle.style.left = '0'
3917
+ * if (isRight) handle.style.right = '0'
3918
+ *
3919
+ * // Edge handles span the full width or height
3920
+ * if (direction === 'top' || direction === 'bottom') {
3921
+ * handle.style.left = '0'
3922
+ * handle.style.right = '0'
3923
+ * }
3924
+ *
3925
+ * if (direction === 'left' || direction === 'right') {
3926
+ * handle.style.top = '0'
3927
+ * handle.style.bottom = '0'
3928
+ * }
3929
+ *
3930
+ * return handle
3931
+ * }
3932
+ * ```
3933
+ */
3934
+ createCustomHandle?: (direction: ResizableNodeViewDirection) => HTMLElement;
3887
3935
  };
3888
3936
  };
3889
3937
  /**
@@ -3925,6 +3973,8 @@ type ResizableNodeViewOptions = {
3925
3973
  declare class ResizableNodeView {
3926
3974
  /** The ProseMirror node instance */
3927
3975
  node: Node$1;
3976
+ /** The Tiptap editor instance */
3977
+ editor: Editor;
3928
3978
  /** The DOM element being made resizable */
3929
3979
  element: HTMLElement;
3930
3980
  /** The editable DOM element inside the DOM */
@@ -3956,6 +4006,8 @@ declare class ResizableNodeView {
3956
4006
  handle: string;
3957
4007
  resizing: string;
3958
4008
  };
4009
+ /** Optional callback for creating custom resize handles */
4010
+ createCustomHandle?: (direction: ResizableNodeViewDirection) => HTMLElement;
3959
4011
  /** Initial width of the element (for aspect ratio calculation) */
3960
4012
  private initialWidth;
3961
4013
  /** Initial height of the element (for aspect ratio calculation) */
@@ -3976,6 +4028,10 @@ declare class ResizableNodeView {
3976
4028
  private startHeight;
3977
4029
  /** Whether Shift key is currently pressed (for temporary aspect ratio lock) */
3978
4030
  private isShiftKeyPressed;
4031
+ /** Last known editable state of the editor */
4032
+ private lastEditableState;
4033
+ /** Map of handle elements by direction */
4034
+ private handleMap;
3979
4035
  /**
3980
4036
  * Creates a new ResizableNodeView instance.
3981
4037
  *
@@ -3995,6 +4051,7 @@ declare class ResizableNodeView {
3995
4051
  */
3996
4052
  get dom(): HTMLElement;
3997
4053
  get contentDOM(): HTMLElement | undefined;
4054
+ private handleEditorUpdate;
3998
4055
  /**
3999
4056
  * Called when the node's content or attributes change.
4000
4057
  *
@@ -4062,6 +4119,12 @@ declare class ResizableNodeView {
4062
4119
  * positions it, attaches the mousedown listener, and appends it to the DOM.
4063
4120
  */
4064
4121
  private attachHandles;
4122
+ /**
4123
+ * Removes all resize handles from the wrapper.
4124
+ *
4125
+ * Cleans up the handle map and removes each handle element from the DOM.
4126
+ */
4127
+ private removeHandles;
4065
4128
  /**
4066
4129
  * Applies initial sizing from node attributes to the element.
4067
4130
  *
@@ -4455,6 +4518,20 @@ declare function createBlockMarkdownSpec(options: BlockMarkdownSpecOptions): {
4455
4518
  renderMarkdown: (node: JSONContent, h: MarkdownRendererHelpers) => string;
4456
4519
  };
4457
4520
 
4521
+ /**
4522
+ * Configuration for an allowed attribute in markdown serialization.
4523
+ * Can be a simple string (attribute name) or an object with additional options.
4524
+ */
4525
+ type AllowedAttribute = string | {
4526
+ /** The attribute name */
4527
+ name: string;
4528
+ /**
4529
+ * If provided, the attribute will be skipped during serialization when its value
4530
+ * equals this default value. This keeps markdown output clean by omitting
4531
+ * attributes that have their default values.
4532
+ */
4533
+ skipIfDefault?: any;
4534
+ };
4458
4535
  interface InlineMarkdownSpecOptions {
4459
4536
  /** The Tiptap node name this spec is for */
4460
4537
  nodeName: string;
@@ -4470,8 +4547,26 @@ interface InlineMarkdownSpecOptions {
4470
4547
  defaultAttributes?: Record<string, any>;
4471
4548
  /** Whether this is a self-closing shortcode (no content, like [emoji name=party]) */
4472
4549
  selfClosing?: boolean;
4473
- /** Allowlist of attributes to include in markdown (if not provided, all attributes are included) */
4474
- allowedAttributes?: string[];
4550
+ /**
4551
+ * Allowlist of attributes to include in markdown serialization.
4552
+ * If not provided, all attributes are included.
4553
+ *
4554
+ * Each item can be either:
4555
+ * - A string: the attribute name (always included if present)
4556
+ * - An object: `{ name: string, skipIfDefault?: any }` for conditional inclusion
4557
+ *
4558
+ * @example
4559
+ * // Simple string attributes (backward compatible)
4560
+ * allowedAttributes: ['id', 'label']
4561
+ *
4562
+ * // Mixed with conditional attributes
4563
+ * allowedAttributes: [
4564
+ * 'id',
4565
+ * 'label',
4566
+ * { name: 'mentionSuggestionChar', skipIfDefault: '@' }
4567
+ * ]
4568
+ */
4569
+ allowedAttributes?: AllowedAttribute[];
4475
4570
  }
4476
4571
  /**
4477
4572
  * Creates a complete markdown spec for inline nodes using attribute syntax.
@@ -4669,6 +4764,7 @@ declare function renderNestedMarkdownContent(node: JSONContent, h: {
4669
4764
  * for different types of nodes using unified syntax patterns.
4670
4765
  */
4671
4766
 
4767
+ type index_AllowedAttribute = AllowedAttribute;
4672
4768
  type index_AtomBlockMarkdownSpecOptions = AtomBlockMarkdownSpecOptions;
4673
4769
  type index_BlockMarkdownSpecOptions = BlockMarkdownSpecOptions;
4674
4770
  type index_BlockParserConfig = BlockParserConfig;
@@ -4682,7 +4778,7 @@ declare const index_parseIndentedBlocks: typeof parseIndentedBlocks;
4682
4778
  declare const index_renderNestedMarkdownContent: typeof renderNestedMarkdownContent;
4683
4779
  declare const index_serializeAttributes: typeof serializeAttributes;
4684
4780
  declare namespace index {
4685
- export { type index_AtomBlockMarkdownSpecOptions as AtomBlockMarkdownSpecOptions, type index_BlockMarkdownSpecOptions as BlockMarkdownSpecOptions, type index_BlockParserConfig as BlockParserConfig, type index_InlineMarkdownSpecOptions as InlineMarkdownSpecOptions, type index_ParsedBlock as ParsedBlock, index_createAtomBlockMarkdownSpec as createAtomBlockMarkdownSpec, index_createBlockMarkdownSpec as createBlockMarkdownSpec, index_createInlineMarkdownSpec as createInlineMarkdownSpec, index_parseAttributes as parseAttributes, index_parseIndentedBlocks as parseIndentedBlocks, index_renderNestedMarkdownContent as renderNestedMarkdownContent, index_serializeAttributes as serializeAttributes };
4781
+ export { type index_AllowedAttribute as AllowedAttribute, type index_AtomBlockMarkdownSpecOptions as AtomBlockMarkdownSpecOptions, type index_BlockMarkdownSpecOptions as BlockMarkdownSpecOptions, type index_BlockParserConfig as BlockParserConfig, type index_InlineMarkdownSpecOptions as InlineMarkdownSpecOptions, type index_ParsedBlock as ParsedBlock, index_createAtomBlockMarkdownSpec as createAtomBlockMarkdownSpec, index_createBlockMarkdownSpec as createBlockMarkdownSpec, index_createInlineMarkdownSpec as createInlineMarkdownSpec, index_parseAttributes as parseAttributes, index_parseIndentedBlocks as parseIndentedBlocks, index_renderNestedMarkdownContent as renderNestedMarkdownContent, index_serializeAttributes as serializeAttributes };
4686
4782
  }
4687
4783
 
4688
4784
  declare function mergeAttributes(...objects: Record<string, any>[]): Record<string, any>;
@@ -4714,4 +4810,4 @@ interface Commands<ReturnType = any> {
4714
4810
  interface Storage {
4715
4811
  }
4716
4812
 
4717
- export { type AnyCommands, type AnyConfig, type AnyExtension, type AtomBlockMarkdownSpecOptions, type Attribute, type Attributes$1 as Attributes, type BlockMarkdownSpecOptions, type BlockParserConfig, type CanCommands, type ChainedCommands, type ChangedRange, type Command, CommandManager, type CommandProps, type CommandSpec, type Commands, type Content, type CreateNodeFromContentOptions, type DOMNode, type DOMOutputSpecArray$1 as DOMOutputSpecArray, type DecorationType, type DecorationWithType, type Diff, type Dispatch, type DocumentType, Editor, type EditorEvents, type EditorOptions, type EnableRules, Extendable, type ExtendableConfig, type ExtendedRegExpMatchArray, Extension, type ExtensionAttribute, type ExtensionConfig, type Extensions, type FocusPosition, Fragment, type FullMarkdownHelpers, type GetUpdatedPositionResult, type GlobalAttributes, type HTMLContent, type InlineMarkdownSpecOptions, InputRule, type InputRuleFinder, type InputRuleMatch, type InsertContentAtOptions, type InsertContentOptions, type JSONContent, type KeyboardShortcutCommand, type KeysWithTypeOf, MappablePosition, Mark, type MarkConfig, type MarkRange, type MarkType, MarkView, type MarkViewProps, type MarkViewRenderer, type MarkViewRendererOptions, type MarkViewRendererProps, type MarkdownExtensionSpec, type MarkdownHelpers, type MarkdownLexerConfiguration, type MarkdownParseHelpers, type MarkdownParseResult, type MarkdownRendererHelpers, type MarkdownToken, type MarkdownTokenizer, type MaybeReturnType, type MaybeThisParameterType, Node, type NodeConfig, NodePos, type NodeRange, type NodeType, NodeView, type NodeViewProps, type NodeViewRenderer, type NodeViewRendererOptions, type NodeViewRendererProps, type NodeWithPos, type Overwrite, type ParentConfig, type ParsedBlock, PasteRule, type PasteRuleFinder, type PasteRuleMatch, type PickValue, type Predicate, type Primitive, type Range, type RawCommands, type RemoveThis, type RenderContext, type ResizableNodeDimensions, ResizableNodeView, type ResizableNodeViewDirection, type ResizableNodeViewOptions, ResizableNodeview, type SetContentOptions, type SingleCommands, type Storage, type TextSerializer, type TextType, type TiptapEditorHTMLElement, Tracker, type TrackerResult, type UnionCommands, type UnionToIntersection, type Utils, type ValuesOf, blur, callOrReturn, canInsertNode, clearContent, clearNodes, combineTransactionSteps, command, index$2 as commands, createAtomBlockMarkdownSpec, createBlockMarkdownSpec, createChainableState, createDocument, h as createElement, createInlineMarkdownSpec, createMappablePosition, createNodeFromContent, createParagraphNear, createStyleTag, cut, defaultBlockAt, deleteCurrentNode, deleteNode, deleteProps, deleteRange, deleteSelection, elementFromString, enter, escapeForRegEx, exitCode, extendMarkRange, index$1 as extensions, findChildren, findChildrenInRange, findDuplicates, findParentNode, findParentNodeClosestToPos, first, flattenExtensions, focus, forEach, fromString, generateHTML, generateJSON, generateText, getAttributes, getAttributesFromExtensions, getChangedRanges, getDebugJSON, getExtensionField, getHTMLFromFragment, getMarkAttributes, getMarkRange, getMarkType, getMarksBetween, getNodeAtPosition, getNodeAttributes, getNodeType, getRenderedAttributes, getSchema, getSchemaByResolvedExtensions, getSchemaTypeByName, getSchemaTypeNameByName, getSplittedAttributes, getText, getTextBetween, getTextContentFromNodes, getTextSerializersFromSchema, getUpdatedPosition, h, injectExtensionAttributesToParseRule, inputRulesPlugin, insertContent, insertContentAt, isActive, isAndroid, isAtEndOfNode, isAtStartOfNode, isEmptyObject, isExtensionRulesEnabled, isFunction, isList, isMacOS, isMarkActive, isNodeActive, isNodeEmpty, isNodeSelection, isNumber, isPlainObject, isRegExp, isString, isTextSelection, isiOS, joinBackward, joinDown, joinForward, joinItemBackward, joinItemForward, joinTextblockBackward, joinTextblockForward, joinUp, keyboardShortcut, lift, liftEmptyBlock, liftListItem, markInputRule, markPasteRule, index as markdown, mergeAttributes, mergeDeep, minMax, newlineInCode, nodeInputRule, nodePasteRule, objectIncludes, parseAttributes, parseIndentedBlocks, pasteRulesPlugin, posToDOMRect, removeDuplicates, renderNestedMarkdownContent, resetAttributes, resolveExtensions, resolveFocusPosition, rewriteUnknownContent, scrollIntoView, selectAll, selectNodeBackward, selectNodeForward, selectParentNode, selectTextblockEnd, selectTextblockStart, selectionToInsertionEnd, serializeAttributes, setContent, setMark, setMeta, setNode, setNodeSelection, setTextDirection, setTextSelection, sinkListItem, sortExtensions, splitBlock, splitExtensions, splitListItem, textInputRule, textPasteRule, textblockTypeInputRule, toggleList, toggleMark, toggleNode, toggleWrap, undoInputRule, unsetAllMarks, unsetMark, unsetTextDirection, updateAttributes, updateMarkViewAttributes, wrapIn, wrapInList, wrappingInputRule };
4813
+ export { type AllowedAttribute, type AnyCommands, type AnyConfig, type AnyExtension, type AtomBlockMarkdownSpecOptions, type Attribute, type Attributes$1 as Attributes, type BlockMarkdownSpecOptions, type BlockParserConfig, type CanCommands, type ChainedCommands, type ChangedRange, type Command, CommandManager, type CommandProps, type CommandSpec, type Commands, type Content, type CreateNodeFromContentOptions, type DOMNode, type DOMOutputSpecArray$1 as DOMOutputSpecArray, type DecorationType, type DecorationWithType, type Diff, type Dispatch, type DocumentType, Editor, type EditorEvents, type EditorOptions, type EnableRules, Extendable, type ExtendableConfig, type ExtendedRegExpMatchArray, Extension, type ExtensionAttribute, type ExtensionConfig, type Extensions, type FocusPosition, Fragment, type FullMarkdownHelpers, type GetUpdatedPositionResult, type GlobalAttributes, type HTMLContent, type InlineMarkdownSpecOptions, InputRule, type InputRuleFinder, type InputRuleMatch, type InsertContentAtOptions, type InsertContentOptions, type JSONContent, type KeyboardShortcutCommand, type KeysWithTypeOf, MappablePosition, Mark, type MarkConfig, type MarkRange, type MarkType, MarkView, type MarkViewProps, type MarkViewRenderer, type MarkViewRendererOptions, type MarkViewRendererProps, type MarkdownExtensionSpec, type MarkdownHelpers, type MarkdownLexerConfiguration, type MarkdownParseHelpers, type MarkdownParseResult, type MarkdownRendererHelpers, type MarkdownToken, type MarkdownTokenizer, type MaybeReturnType, type MaybeThisParameterType, Node, type NodeConfig, NodePos, type NodeRange, type NodeType, NodeView, type NodeViewProps, type NodeViewRenderer, type NodeViewRendererOptions, type NodeViewRendererProps, type NodeWithPos, type Overwrite, type ParentConfig, type ParsedBlock, PasteRule, type PasteRuleFinder, type PasteRuleMatch, type PickValue, type Predicate, type Primitive, type Range, type RawCommands, type RemoveThis, type RenderContext, type ResizableNodeDimensions, ResizableNodeView, type ResizableNodeViewDirection, type ResizableNodeViewOptions, ResizableNodeview, type SetContentOptions, type SingleCommands, type Storage, type TextSerializer, type TextType, type TiptapEditorHTMLElement, Tracker, type TrackerResult, type UnionCommands, type UnionToIntersection, type Utils, type ValuesOf, blur, callOrReturn, canInsertNode, clearContent, clearNodes, combineTransactionSteps, command, index$2 as commands, createAtomBlockMarkdownSpec, createBlockMarkdownSpec, createChainableState, createDocument, h as createElement, createInlineMarkdownSpec, createMappablePosition, createNodeFromContent, createParagraphNear, createStyleTag, cut, defaultBlockAt, deleteCurrentNode, deleteNode, deleteProps, deleteRange, deleteSelection, elementFromString, enter, escapeForRegEx, exitCode, extendMarkRange, index$1 as extensions, findChildren, findChildrenInRange, findDuplicates, findParentNode, findParentNodeClosestToPos, first, flattenExtensions, focus, forEach, fromString, generateHTML, generateJSON, generateText, getAttributes, getAttributesFromExtensions, getChangedRanges, getDebugJSON, getExtensionField, getHTMLFromFragment, getMarkAttributes, getMarkRange, getMarkType, getMarksBetween, getNodeAtPosition, getNodeAttributes, getNodeType, getRenderedAttributes, getSchema, getSchemaByResolvedExtensions, getSchemaTypeByName, getSchemaTypeNameByName, getSplittedAttributes, getText, getTextBetween, getTextContentFromNodes, getTextSerializersFromSchema, getUpdatedPosition, h, injectExtensionAttributesToParseRule, inputRulesPlugin, insertContent, insertContentAt, isActive, isAndroid, isAtEndOfNode, isAtStartOfNode, isEmptyObject, isExtensionRulesEnabled, isFunction, isList, isMacOS, isMarkActive, isNodeActive, isNodeEmpty, isNodeSelection, isNumber, isPlainObject, isRegExp, isString, isTextSelection, isiOS, joinBackward, joinDown, joinForward, joinItemBackward, joinItemForward, joinTextblockBackward, joinTextblockForward, joinUp, keyboardShortcut, lift, liftEmptyBlock, liftListItem, markInputRule, markPasteRule, index as markdown, mergeAttributes, mergeDeep, minMax, newlineInCode, nodeInputRule, nodePasteRule, objectIncludes, parseAttributes, parseIndentedBlocks, pasteRulesPlugin, posToDOMRect, removeDuplicates, renderNestedMarkdownContent, resetAttributes, resolveExtensions, resolveFocusPosition, rewriteUnknownContent, scrollIntoView, selectAll, selectNodeBackward, selectNodeForward, selectParentNode, selectTextblockEnd, selectTextblockStart, selectionToInsertionEnd, serializeAttributes, setContent, setMark, setMeta, setNode, setNodeSelection, setTextDirection, setTextSelection, sinkListItem, sortExtensions, splitBlock, splitExtensions, splitListItem, textInputRule, textPasteRule, textblockTypeInputRule, toggleList, toggleMark, toggleNode, toggleWrap, undoInputRule, unsetAllMarks, unsetMark, unsetTextDirection, updateAttributes, updateMarkViewAttributes, wrapIn, wrapInList, wrappingInputRule };
package/dist/index.d.ts CHANGED
@@ -3761,6 +3761,10 @@ type ResizableNodeViewOptions = {
3761
3761
  * The ProseMirror node instance
3762
3762
  */
3763
3763
  node: Node$1;
3764
+ /**
3765
+ * The Tiptap editor instance
3766
+ */
3767
+ editor: Editor;
3764
3768
  /**
3765
3769
  * Function that returns the current position of the node in the document
3766
3770
  */
@@ -3884,6 +3888,50 @@ type ResizableNodeViewOptions = {
3884
3888
  /** Class added to container while actively resizing */
3885
3889
  resizing?: string;
3886
3890
  };
3891
+ /**
3892
+ * Optional callback for creating custom resize handle elements.
3893
+ *
3894
+ * This function allows developers to define their own handle element
3895
+ * (e.g., custom icons, classes, or styles) for a given resize direction.
3896
+ * It is called internally for each handle direction.
3897
+ *
3898
+ * @param direction - The direction of the handle being created (e.g., 'top', 'bottom-right').
3899
+ * @returns The custom handle HTMLElement.
3900
+ *
3901
+ * @example
3902
+ * ```ts
3903
+ * createCustomHandle: (direction) => {
3904
+ * const handle = document.createElement('div')
3905
+ * handle.dataset.resizeHandle = direction
3906
+ * handle.style.position = 'absolute'
3907
+ * handle.className = 'tiptap-custom-handle'
3908
+ *
3909
+ * const isTop = direction.includes('top')
3910
+ * const isBottom = direction.includes('bottom')
3911
+ * const isLeft = direction.includes('left')
3912
+ * const isRight = direction.includes('right')
3913
+ *
3914
+ * if (isTop) handle.style.top = '0'
3915
+ * if (isBottom) handle.style.bottom = '0'
3916
+ * if (isLeft) handle.style.left = '0'
3917
+ * if (isRight) handle.style.right = '0'
3918
+ *
3919
+ * // Edge handles span the full width or height
3920
+ * if (direction === 'top' || direction === 'bottom') {
3921
+ * handle.style.left = '0'
3922
+ * handle.style.right = '0'
3923
+ * }
3924
+ *
3925
+ * if (direction === 'left' || direction === 'right') {
3926
+ * handle.style.top = '0'
3927
+ * handle.style.bottom = '0'
3928
+ * }
3929
+ *
3930
+ * return handle
3931
+ * }
3932
+ * ```
3933
+ */
3934
+ createCustomHandle?: (direction: ResizableNodeViewDirection) => HTMLElement;
3887
3935
  };
3888
3936
  };
3889
3937
  /**
@@ -3925,6 +3973,8 @@ type ResizableNodeViewOptions = {
3925
3973
  declare class ResizableNodeView {
3926
3974
  /** The ProseMirror node instance */
3927
3975
  node: Node$1;
3976
+ /** The Tiptap editor instance */
3977
+ editor: Editor;
3928
3978
  /** The DOM element being made resizable */
3929
3979
  element: HTMLElement;
3930
3980
  /** The editable DOM element inside the DOM */
@@ -3956,6 +4006,8 @@ declare class ResizableNodeView {
3956
4006
  handle: string;
3957
4007
  resizing: string;
3958
4008
  };
4009
+ /** Optional callback for creating custom resize handles */
4010
+ createCustomHandle?: (direction: ResizableNodeViewDirection) => HTMLElement;
3959
4011
  /** Initial width of the element (for aspect ratio calculation) */
3960
4012
  private initialWidth;
3961
4013
  /** Initial height of the element (for aspect ratio calculation) */
@@ -3976,6 +4028,10 @@ declare class ResizableNodeView {
3976
4028
  private startHeight;
3977
4029
  /** Whether Shift key is currently pressed (for temporary aspect ratio lock) */
3978
4030
  private isShiftKeyPressed;
4031
+ /** Last known editable state of the editor */
4032
+ private lastEditableState;
4033
+ /** Map of handle elements by direction */
4034
+ private handleMap;
3979
4035
  /**
3980
4036
  * Creates a new ResizableNodeView instance.
3981
4037
  *
@@ -3995,6 +4051,7 @@ declare class ResizableNodeView {
3995
4051
  */
3996
4052
  get dom(): HTMLElement;
3997
4053
  get contentDOM(): HTMLElement | undefined;
4054
+ private handleEditorUpdate;
3998
4055
  /**
3999
4056
  * Called when the node's content or attributes change.
4000
4057
  *
@@ -4062,6 +4119,12 @@ declare class ResizableNodeView {
4062
4119
  * positions it, attaches the mousedown listener, and appends it to the DOM.
4063
4120
  */
4064
4121
  private attachHandles;
4122
+ /**
4123
+ * Removes all resize handles from the wrapper.
4124
+ *
4125
+ * Cleans up the handle map and removes each handle element from the DOM.
4126
+ */
4127
+ private removeHandles;
4065
4128
  /**
4066
4129
  * Applies initial sizing from node attributes to the element.
4067
4130
  *
@@ -4455,6 +4518,20 @@ declare function createBlockMarkdownSpec(options: BlockMarkdownSpecOptions): {
4455
4518
  renderMarkdown: (node: JSONContent, h: MarkdownRendererHelpers) => string;
4456
4519
  };
4457
4520
 
4521
+ /**
4522
+ * Configuration for an allowed attribute in markdown serialization.
4523
+ * Can be a simple string (attribute name) or an object with additional options.
4524
+ */
4525
+ type AllowedAttribute = string | {
4526
+ /** The attribute name */
4527
+ name: string;
4528
+ /**
4529
+ * If provided, the attribute will be skipped during serialization when its value
4530
+ * equals this default value. This keeps markdown output clean by omitting
4531
+ * attributes that have their default values.
4532
+ */
4533
+ skipIfDefault?: any;
4534
+ };
4458
4535
  interface InlineMarkdownSpecOptions {
4459
4536
  /** The Tiptap node name this spec is for */
4460
4537
  nodeName: string;
@@ -4470,8 +4547,26 @@ interface InlineMarkdownSpecOptions {
4470
4547
  defaultAttributes?: Record<string, any>;
4471
4548
  /** Whether this is a self-closing shortcode (no content, like [emoji name=party]) */
4472
4549
  selfClosing?: boolean;
4473
- /** Allowlist of attributes to include in markdown (if not provided, all attributes are included) */
4474
- allowedAttributes?: string[];
4550
+ /**
4551
+ * Allowlist of attributes to include in markdown serialization.
4552
+ * If not provided, all attributes are included.
4553
+ *
4554
+ * Each item can be either:
4555
+ * - A string: the attribute name (always included if present)
4556
+ * - An object: `{ name: string, skipIfDefault?: any }` for conditional inclusion
4557
+ *
4558
+ * @example
4559
+ * // Simple string attributes (backward compatible)
4560
+ * allowedAttributes: ['id', 'label']
4561
+ *
4562
+ * // Mixed with conditional attributes
4563
+ * allowedAttributes: [
4564
+ * 'id',
4565
+ * 'label',
4566
+ * { name: 'mentionSuggestionChar', skipIfDefault: '@' }
4567
+ * ]
4568
+ */
4569
+ allowedAttributes?: AllowedAttribute[];
4475
4570
  }
4476
4571
  /**
4477
4572
  * Creates a complete markdown spec for inline nodes using attribute syntax.
@@ -4669,6 +4764,7 @@ declare function renderNestedMarkdownContent(node: JSONContent, h: {
4669
4764
  * for different types of nodes using unified syntax patterns.
4670
4765
  */
4671
4766
 
4767
+ type index_AllowedAttribute = AllowedAttribute;
4672
4768
  type index_AtomBlockMarkdownSpecOptions = AtomBlockMarkdownSpecOptions;
4673
4769
  type index_BlockMarkdownSpecOptions = BlockMarkdownSpecOptions;
4674
4770
  type index_BlockParserConfig = BlockParserConfig;
@@ -4682,7 +4778,7 @@ declare const index_parseIndentedBlocks: typeof parseIndentedBlocks;
4682
4778
  declare const index_renderNestedMarkdownContent: typeof renderNestedMarkdownContent;
4683
4779
  declare const index_serializeAttributes: typeof serializeAttributes;
4684
4780
  declare namespace index {
4685
- export { type index_AtomBlockMarkdownSpecOptions as AtomBlockMarkdownSpecOptions, type index_BlockMarkdownSpecOptions as BlockMarkdownSpecOptions, type index_BlockParserConfig as BlockParserConfig, type index_InlineMarkdownSpecOptions as InlineMarkdownSpecOptions, type index_ParsedBlock as ParsedBlock, index_createAtomBlockMarkdownSpec as createAtomBlockMarkdownSpec, index_createBlockMarkdownSpec as createBlockMarkdownSpec, index_createInlineMarkdownSpec as createInlineMarkdownSpec, index_parseAttributes as parseAttributes, index_parseIndentedBlocks as parseIndentedBlocks, index_renderNestedMarkdownContent as renderNestedMarkdownContent, index_serializeAttributes as serializeAttributes };
4781
+ export { type index_AllowedAttribute as AllowedAttribute, type index_AtomBlockMarkdownSpecOptions as AtomBlockMarkdownSpecOptions, type index_BlockMarkdownSpecOptions as BlockMarkdownSpecOptions, type index_BlockParserConfig as BlockParserConfig, type index_InlineMarkdownSpecOptions as InlineMarkdownSpecOptions, type index_ParsedBlock as ParsedBlock, index_createAtomBlockMarkdownSpec as createAtomBlockMarkdownSpec, index_createBlockMarkdownSpec as createBlockMarkdownSpec, index_createInlineMarkdownSpec as createInlineMarkdownSpec, index_parseAttributes as parseAttributes, index_parseIndentedBlocks as parseIndentedBlocks, index_renderNestedMarkdownContent as renderNestedMarkdownContent, index_serializeAttributes as serializeAttributes };
4686
4782
  }
4687
4783
 
4688
4784
  declare function mergeAttributes(...objects: Record<string, any>[]): Record<string, any>;
@@ -4714,4 +4810,4 @@ interface Commands<ReturnType = any> {
4714
4810
  interface Storage {
4715
4811
  }
4716
4812
 
4717
- export { type AnyCommands, type AnyConfig, type AnyExtension, type AtomBlockMarkdownSpecOptions, type Attribute, type Attributes$1 as Attributes, type BlockMarkdownSpecOptions, type BlockParserConfig, type CanCommands, type ChainedCommands, type ChangedRange, type Command, CommandManager, type CommandProps, type CommandSpec, type Commands, type Content, type CreateNodeFromContentOptions, type DOMNode, type DOMOutputSpecArray$1 as DOMOutputSpecArray, type DecorationType, type DecorationWithType, type Diff, type Dispatch, type DocumentType, Editor, type EditorEvents, type EditorOptions, type EnableRules, Extendable, type ExtendableConfig, type ExtendedRegExpMatchArray, Extension, type ExtensionAttribute, type ExtensionConfig, type Extensions, type FocusPosition, Fragment, type FullMarkdownHelpers, type GetUpdatedPositionResult, type GlobalAttributes, type HTMLContent, type InlineMarkdownSpecOptions, InputRule, type InputRuleFinder, type InputRuleMatch, type InsertContentAtOptions, type InsertContentOptions, type JSONContent, type KeyboardShortcutCommand, type KeysWithTypeOf, MappablePosition, Mark, type MarkConfig, type MarkRange, type MarkType, MarkView, type MarkViewProps, type MarkViewRenderer, type MarkViewRendererOptions, type MarkViewRendererProps, type MarkdownExtensionSpec, type MarkdownHelpers, type MarkdownLexerConfiguration, type MarkdownParseHelpers, type MarkdownParseResult, type MarkdownRendererHelpers, type MarkdownToken, type MarkdownTokenizer, type MaybeReturnType, type MaybeThisParameterType, Node, type NodeConfig, NodePos, type NodeRange, type NodeType, NodeView, type NodeViewProps, type NodeViewRenderer, type NodeViewRendererOptions, type NodeViewRendererProps, type NodeWithPos, type Overwrite, type ParentConfig, type ParsedBlock, PasteRule, type PasteRuleFinder, type PasteRuleMatch, type PickValue, type Predicate, type Primitive, type Range, type RawCommands, type RemoveThis, type RenderContext, type ResizableNodeDimensions, ResizableNodeView, type ResizableNodeViewDirection, type ResizableNodeViewOptions, ResizableNodeview, type SetContentOptions, type SingleCommands, type Storage, type TextSerializer, type TextType, type TiptapEditorHTMLElement, Tracker, type TrackerResult, type UnionCommands, type UnionToIntersection, type Utils, type ValuesOf, blur, callOrReturn, canInsertNode, clearContent, clearNodes, combineTransactionSteps, command, index$2 as commands, createAtomBlockMarkdownSpec, createBlockMarkdownSpec, createChainableState, createDocument, h as createElement, createInlineMarkdownSpec, createMappablePosition, createNodeFromContent, createParagraphNear, createStyleTag, cut, defaultBlockAt, deleteCurrentNode, deleteNode, deleteProps, deleteRange, deleteSelection, elementFromString, enter, escapeForRegEx, exitCode, extendMarkRange, index$1 as extensions, findChildren, findChildrenInRange, findDuplicates, findParentNode, findParentNodeClosestToPos, first, flattenExtensions, focus, forEach, fromString, generateHTML, generateJSON, generateText, getAttributes, getAttributesFromExtensions, getChangedRanges, getDebugJSON, getExtensionField, getHTMLFromFragment, getMarkAttributes, getMarkRange, getMarkType, getMarksBetween, getNodeAtPosition, getNodeAttributes, getNodeType, getRenderedAttributes, getSchema, getSchemaByResolvedExtensions, getSchemaTypeByName, getSchemaTypeNameByName, getSplittedAttributes, getText, getTextBetween, getTextContentFromNodes, getTextSerializersFromSchema, getUpdatedPosition, h, injectExtensionAttributesToParseRule, inputRulesPlugin, insertContent, insertContentAt, isActive, isAndroid, isAtEndOfNode, isAtStartOfNode, isEmptyObject, isExtensionRulesEnabled, isFunction, isList, isMacOS, isMarkActive, isNodeActive, isNodeEmpty, isNodeSelection, isNumber, isPlainObject, isRegExp, isString, isTextSelection, isiOS, joinBackward, joinDown, joinForward, joinItemBackward, joinItemForward, joinTextblockBackward, joinTextblockForward, joinUp, keyboardShortcut, lift, liftEmptyBlock, liftListItem, markInputRule, markPasteRule, index as markdown, mergeAttributes, mergeDeep, minMax, newlineInCode, nodeInputRule, nodePasteRule, objectIncludes, parseAttributes, parseIndentedBlocks, pasteRulesPlugin, posToDOMRect, removeDuplicates, renderNestedMarkdownContent, resetAttributes, resolveExtensions, resolveFocusPosition, rewriteUnknownContent, scrollIntoView, selectAll, selectNodeBackward, selectNodeForward, selectParentNode, selectTextblockEnd, selectTextblockStart, selectionToInsertionEnd, serializeAttributes, setContent, setMark, setMeta, setNode, setNodeSelection, setTextDirection, setTextSelection, sinkListItem, sortExtensions, splitBlock, splitExtensions, splitListItem, textInputRule, textPasteRule, textblockTypeInputRule, toggleList, toggleMark, toggleNode, toggleWrap, undoInputRule, unsetAllMarks, unsetMark, unsetTextDirection, updateAttributes, updateMarkViewAttributes, wrapIn, wrapInList, wrappingInputRule };
4813
+ export { type AllowedAttribute, type AnyCommands, type AnyConfig, type AnyExtension, type AtomBlockMarkdownSpecOptions, type Attribute, type Attributes$1 as Attributes, type BlockMarkdownSpecOptions, type BlockParserConfig, type CanCommands, type ChainedCommands, type ChangedRange, type Command, CommandManager, type CommandProps, type CommandSpec, type Commands, type Content, type CreateNodeFromContentOptions, type DOMNode, type DOMOutputSpecArray$1 as DOMOutputSpecArray, type DecorationType, type DecorationWithType, type Diff, type Dispatch, type DocumentType, Editor, type EditorEvents, type EditorOptions, type EnableRules, Extendable, type ExtendableConfig, type ExtendedRegExpMatchArray, Extension, type ExtensionAttribute, type ExtensionConfig, type Extensions, type FocusPosition, Fragment, type FullMarkdownHelpers, type GetUpdatedPositionResult, type GlobalAttributes, type HTMLContent, type InlineMarkdownSpecOptions, InputRule, type InputRuleFinder, type InputRuleMatch, type InsertContentAtOptions, type InsertContentOptions, type JSONContent, type KeyboardShortcutCommand, type KeysWithTypeOf, MappablePosition, Mark, type MarkConfig, type MarkRange, type MarkType, MarkView, type MarkViewProps, type MarkViewRenderer, type MarkViewRendererOptions, type MarkViewRendererProps, type MarkdownExtensionSpec, type MarkdownHelpers, type MarkdownLexerConfiguration, type MarkdownParseHelpers, type MarkdownParseResult, type MarkdownRendererHelpers, type MarkdownToken, type MarkdownTokenizer, type MaybeReturnType, type MaybeThisParameterType, Node, type NodeConfig, NodePos, type NodeRange, type NodeType, NodeView, type NodeViewProps, type NodeViewRenderer, type NodeViewRendererOptions, type NodeViewRendererProps, type NodeWithPos, type Overwrite, type ParentConfig, type ParsedBlock, PasteRule, type PasteRuleFinder, type PasteRuleMatch, type PickValue, type Predicate, type Primitive, type Range, type RawCommands, type RemoveThis, type RenderContext, type ResizableNodeDimensions, ResizableNodeView, type ResizableNodeViewDirection, type ResizableNodeViewOptions, ResizableNodeview, type SetContentOptions, type SingleCommands, type Storage, type TextSerializer, type TextType, type TiptapEditorHTMLElement, Tracker, type TrackerResult, type UnionCommands, type UnionToIntersection, type Utils, type ValuesOf, blur, callOrReturn, canInsertNode, clearContent, clearNodes, combineTransactionSteps, command, index$2 as commands, createAtomBlockMarkdownSpec, createBlockMarkdownSpec, createChainableState, createDocument, h as createElement, createInlineMarkdownSpec, createMappablePosition, createNodeFromContent, createParagraphNear, createStyleTag, cut, defaultBlockAt, deleteCurrentNode, deleteNode, deleteProps, deleteRange, deleteSelection, elementFromString, enter, escapeForRegEx, exitCode, extendMarkRange, index$1 as extensions, findChildren, findChildrenInRange, findDuplicates, findParentNode, findParentNodeClosestToPos, first, flattenExtensions, focus, forEach, fromString, generateHTML, generateJSON, generateText, getAttributes, getAttributesFromExtensions, getChangedRanges, getDebugJSON, getExtensionField, getHTMLFromFragment, getMarkAttributes, getMarkRange, getMarkType, getMarksBetween, getNodeAtPosition, getNodeAttributes, getNodeType, getRenderedAttributes, getSchema, getSchemaByResolvedExtensions, getSchemaTypeByName, getSchemaTypeNameByName, getSplittedAttributes, getText, getTextBetween, getTextContentFromNodes, getTextSerializersFromSchema, getUpdatedPosition, h, injectExtensionAttributesToParseRule, inputRulesPlugin, insertContent, insertContentAt, isActive, isAndroid, isAtEndOfNode, isAtStartOfNode, isEmptyObject, isExtensionRulesEnabled, isFunction, isList, isMacOS, isMarkActive, isNodeActive, isNodeEmpty, isNodeSelection, isNumber, isPlainObject, isRegExp, isString, isTextSelection, isiOS, joinBackward, joinDown, joinForward, joinItemBackward, joinItemForward, joinTextblockBackward, joinTextblockForward, joinUp, keyboardShortcut, lift, liftEmptyBlock, liftListItem, markInputRule, markPasteRule, index as markdown, mergeAttributes, mergeDeep, minMax, newlineInCode, nodeInputRule, nodePasteRule, objectIncludes, parseAttributes, parseIndentedBlocks, pasteRulesPlugin, posToDOMRect, removeDuplicates, renderNestedMarkdownContent, resetAttributes, resolveExtensions, resolveFocusPosition, rewriteUnknownContent, scrollIntoView, selectAll, selectNodeBackward, selectNodeForward, selectParentNode, selectTextblockEnd, selectTextblockStart, selectionToInsertionEnd, serializeAttributes, setContent, setMark, setMeta, setNode, setNodeSelection, setTextDirection, setTextSelection, sinkListItem, sortExtensions, splitBlock, splitExtensions, splitListItem, textInputRule, textPasteRule, textblockTypeInputRule, toggleList, toggleMark, toggleNode, toggleWrap, undoInputRule, unsetAllMarks, unsetMark, unsetTextDirection, updateAttributes, updateMarkViewAttributes, wrapIn, wrapInList, wrappingInputRule };
package/dist/index.js CHANGED
@@ -5235,6 +5235,10 @@ var ResizableNodeView = class {
5235
5235
  this.startHeight = 0;
5236
5236
  /** Whether Shift key is currently pressed (for temporary aspect ratio lock) */
5237
5237
  this.isShiftKeyPressed = false;
5238
+ /** Last known editable state of the editor */
5239
+ this.lastEditableState = void 0;
5240
+ /** Map of handle elements by direction */
5241
+ this.handleMap = /* @__PURE__ */ new Map();
5238
5242
  /**
5239
5243
  * Handles mouse movement during an active resize.
5240
5244
  *
@@ -5311,8 +5315,9 @@ var ResizableNodeView = class {
5311
5315
  this.isShiftKeyPressed = false;
5312
5316
  }
5313
5317
  };
5314
- var _a, _b, _c, _d, _e;
5318
+ var _a, _b, _c, _d, _e, _f;
5315
5319
  this.node = options.node;
5320
+ this.editor = options.editor;
5316
5321
  this.element = options.element;
5317
5322
  this.contentElement = options.contentElement;
5318
5323
  this.getPos = options.getPos;
@@ -5342,10 +5347,14 @@ var ResizableNodeView = class {
5342
5347
  resizing: options.options.className.resizing || ""
5343
5348
  };
5344
5349
  }
5350
+ if ((_f = options.options) == null ? void 0 : _f.createCustomHandle) {
5351
+ this.createCustomHandle = options.options.createCustomHandle;
5352
+ }
5345
5353
  this.wrapper = this.createWrapper();
5346
5354
  this.container = this.createContainer();
5347
5355
  this.applyInitialSize();
5348
5356
  this.attachHandles();
5357
+ this.editor.on("update", this.handleEditorUpdate.bind(this));
5349
5358
  }
5350
5359
  /**
5351
5360
  * Returns the top-level DOM node that should be placed in the editor.
@@ -5361,6 +5370,18 @@ var ResizableNodeView = class {
5361
5370
  get contentDOM() {
5362
5371
  return this.contentElement;
5363
5372
  }
5373
+ handleEditorUpdate() {
5374
+ const isEditable = this.editor.isEditable;
5375
+ if (isEditable === this.lastEditableState) {
5376
+ return;
5377
+ }
5378
+ this.lastEditableState = isEditable;
5379
+ if (!isEditable) {
5380
+ this.removeHandles();
5381
+ } else if (isEditable && this.handleMap.size === 0) {
5382
+ this.attachHandles();
5383
+ }
5384
+ }
5364
5385
  /**
5365
5386
  * Called when the node's content or attributes change.
5366
5387
  *
@@ -5402,6 +5423,7 @@ var ResizableNodeView = class {
5402
5423
  this.isResizing = false;
5403
5424
  this.activeHandle = null;
5404
5425
  }
5426
+ this.editor.off("update", this.handleEditorUpdate.bind(this));
5405
5427
  this.container.remove();
5406
5428
  }
5407
5429
  /**
@@ -5418,8 +5440,6 @@ var ResizableNodeView = class {
5418
5440
  element.dataset.resizeContainer = "";
5419
5441
  element.dataset.node = this.node.type.name;
5420
5442
  element.style.display = "flex";
5421
- element.style.justifyContent = "flex-start";
5422
- element.style.alignItems = "flex-start";
5423
5443
  if (this.classNames.container) {
5424
5444
  element.className = this.classNames.container;
5425
5445
  }
@@ -5507,13 +5527,36 @@ var ResizableNodeView = class {
5507
5527
  */
5508
5528
  attachHandles() {
5509
5529
  this.directions.forEach((direction) => {
5510
- const handle = this.createHandle(direction);
5511
- this.positionHandle(handle, direction);
5530
+ let handle;
5531
+ if (this.createCustomHandle) {
5532
+ handle = this.createCustomHandle(direction);
5533
+ } else {
5534
+ handle = this.createHandle(direction);
5535
+ }
5536
+ if (!(handle instanceof HTMLElement)) {
5537
+ console.warn(
5538
+ `[ResizableNodeView] createCustomHandle("${direction}") did not return an HTMLElement. Falling back to default handle.`
5539
+ );
5540
+ handle = this.createHandle(direction);
5541
+ }
5542
+ if (!this.createCustomHandle) {
5543
+ this.positionHandle(handle, direction);
5544
+ }
5512
5545
  handle.addEventListener("mousedown", (event) => this.handleResizeStart(event, direction));
5513
5546
  handle.addEventListener("touchstart", (event) => this.handleResizeStart(event, direction));
5547
+ this.handleMap.set(direction, handle);
5514
5548
  this.wrapper.appendChild(handle);
5515
5549
  });
5516
5550
  }
5551
+ /**
5552
+ * Removes all resize handles from the wrapper.
5553
+ *
5554
+ * Cleans up the handle map and removes each handle element from the DOM.
5555
+ */
5556
+ removeHandles() {
5557
+ this.handleMap.forEach((el) => el.remove());
5558
+ this.handleMap.clear();
5559
+ }
5517
5560
  /**
5518
5561
  * Applies initial sizing from node attributes to the element.
5519
5562
  *
@@ -6060,9 +6103,15 @@ function createInlineMarkdownSpec(options) {
6060
6103
  return attrs;
6061
6104
  }
6062
6105
  const filtered = {};
6063
- allowedAttributes.forEach((key) => {
6064
- if (key in attrs) {
6065
- filtered[key] = attrs[key];
6106
+ allowedAttributes.forEach((attr) => {
6107
+ const attrName = typeof attr === "string" ? attr : attr.name;
6108
+ const skipIfDefault = typeof attr === "string" ? void 0 : attr.skipIfDefault;
6109
+ if (attrName in attrs) {
6110
+ const value = attrs[attrName];
6111
+ if (skipIfDefault !== void 0 && value === skipIfDefault) {
6112
+ return;
6113
+ }
6114
+ filtered[attrName] = value;
6066
6115
  }
6067
6116
  });
6068
6117
  return filtered;