gdpr audit implemented, email log, vollmachten, pdf delete cancel data privacy and vollmachten, removed message no id card in engergy car, and other contracts that are not telecom contracts, added insert counter for engery

This commit is contained in:
2026-03-21 11:59:53 +01:00
parent 89cf92eaf5
commit f2876f877e
1491 changed files with 265550 additions and 1292 deletions
+129
View File
@@ -0,0 +1,129 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/character-count/index.ts
var index_exports = {};
__export(index_exports, {
CharacterCount: () => CharacterCount
});
module.exports = __toCommonJS(index_exports);
// src/character-count/character-count.ts
var import_core = require("@tiptap/core");
var import_state = require("@tiptap/pm/state");
var CharacterCount = import_core.Extension.create({
name: "characterCount",
addOptions() {
return {
limit: null,
mode: "textSize",
textCounter: (text) => text.length,
wordCounter: (text) => text.split(" ").filter((word) => word !== "").length
};
},
addStorage() {
return {
characters: () => 0,
words: () => 0
};
},
onBeforeCreate() {
this.storage.characters = (options) => {
const node = (options == null ? void 0 : options.node) || this.editor.state.doc;
const mode = (options == null ? void 0 : options.mode) || this.options.mode;
if (mode === "textSize") {
const text = node.textBetween(0, node.content.size, void 0, " ");
return this.options.textCounter(text);
}
return node.nodeSize;
};
this.storage.words = (options) => {
const node = (options == null ? void 0 : options.node) || this.editor.state.doc;
const text = node.textBetween(0, node.content.size, " ", " ");
return this.options.wordCounter(text);
};
},
addProseMirrorPlugins() {
let initialEvaluationDone = false;
return [
new import_state.Plugin({
key: new import_state.PluginKey("characterCount"),
appendTransaction: (transactions, oldState, newState) => {
if (initialEvaluationDone) {
return;
}
const limit = this.options.limit;
if (limit === null || limit === void 0 || limit === 0) {
initialEvaluationDone = true;
return;
}
const initialContentSize = this.storage.characters({ node: newState.doc });
if (initialContentSize > limit) {
const over = initialContentSize - limit;
const from = 0;
const to = over;
console.warn(
`[CharacterCount] Initial content exceeded limit of ${limit} characters. Content was automatically trimmed.`
);
const tr = newState.tr.deleteRange(from, to);
initialEvaluationDone = true;
return tr;
}
initialEvaluationDone = true;
},
filterTransaction: (transaction, state) => {
const limit = this.options.limit;
if (!transaction.docChanged || limit === 0 || limit === null || limit === void 0) {
return true;
}
const oldSize = this.storage.characters({ node: state.doc });
const newSize = this.storage.characters({ node: transaction.doc });
if (newSize <= limit) {
return true;
}
if (oldSize > limit && newSize > limit && newSize <= oldSize) {
return true;
}
if (oldSize > limit && newSize > limit && newSize > oldSize) {
return false;
}
const isPaste = transaction.getMeta("paste");
if (!isPaste) {
return false;
}
const pos = transaction.selection.$head.pos;
const over = newSize - limit;
const from = pos - over;
const to = pos;
transaction.deleteRange(from, to);
const updatedSize = this.storage.characters({ node: transaction.doc });
if (updatedSize > limit) {
return false;
}
return true;
}
})
];
}
});
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
CharacterCount
});
//# sourceMappingURL=index.cjs.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,62 @@
import { Extension } from '@tiptap/core';
import { Node } from '@tiptap/pm/model';
interface CharacterCountOptions {
/**
* The maximum number of characters that should be allowed. Defaults to `0`.
* @default null
* @example 180
*/
limit: number | null | undefined;
/**
* The mode by which the size is calculated. If set to `textSize`, the textContent of the document is used.
* If set to `nodeSize`, the nodeSize of the document is used.
* @default 'textSize'
* @example 'textSize'
*/
mode: 'textSize' | 'nodeSize';
/**
* The text counter function to use. Defaults to a simple character count.
* @default (text) => text.length
* @example (text) => [...new Intl.Segmenter().segment(text)].length
*/
textCounter: (text: string) => number;
/**
* The word counter function to use. Defaults to a simple word count.
* @default (text) => text.split(' ').filter(word => word !== '').length
* @example (text) => text.split(/\s+/).filter(word => word !== '').length
*/
wordCounter: (text: string) => number;
}
interface CharacterCountStorage {
/**
* Get the number of characters for the current document.
* @param options The options for the character count. (optional)
* @param options.node The node to get the characters from. Defaults to the current document.
* @param options.mode The mode by which the size is calculated. If set to `textSize`, the textContent of the document is used.
*/
characters: (options?: {
node?: Node;
mode?: 'textSize' | 'nodeSize';
}) => number;
/**
* Get the number of words for the current document.
* @param options The options for the character count. (optional)
* @param options.node The node to get the words from. Defaults to the current document.
*/
words: (options?: {
node?: Node;
}) => number;
}
declare module '@tiptap/core' {
interface Storage {
characterCount: CharacterCountStorage;
}
}
/**
* This extension allows you to count the characters and words of your document.
* @see https://tiptap.dev/api/extensions/character-count
*/
declare const CharacterCount: Extension<CharacterCountOptions, CharacterCountStorage>;
export { CharacterCount, type CharacterCountOptions, type CharacterCountStorage };
@@ -0,0 +1,62 @@
import { Extension } from '@tiptap/core';
import { Node } from '@tiptap/pm/model';
interface CharacterCountOptions {
/**
* The maximum number of characters that should be allowed. Defaults to `0`.
* @default null
* @example 180
*/
limit: number | null | undefined;
/**
* The mode by which the size is calculated. If set to `textSize`, the textContent of the document is used.
* If set to `nodeSize`, the nodeSize of the document is used.
* @default 'textSize'
* @example 'textSize'
*/
mode: 'textSize' | 'nodeSize';
/**
* The text counter function to use. Defaults to a simple character count.
* @default (text) => text.length
* @example (text) => [...new Intl.Segmenter().segment(text)].length
*/
textCounter: (text: string) => number;
/**
* The word counter function to use. Defaults to a simple word count.
* @default (text) => text.split(' ').filter(word => word !== '').length
* @example (text) => text.split(/\s+/).filter(word => word !== '').length
*/
wordCounter: (text: string) => number;
}
interface CharacterCountStorage {
/**
* Get the number of characters for the current document.
* @param options The options for the character count. (optional)
* @param options.node The node to get the characters from. Defaults to the current document.
* @param options.mode The mode by which the size is calculated. If set to `textSize`, the textContent of the document is used.
*/
characters: (options?: {
node?: Node;
mode?: 'textSize' | 'nodeSize';
}) => number;
/**
* Get the number of words for the current document.
* @param options The options for the character count. (optional)
* @param options.node The node to get the words from. Defaults to the current document.
*/
words: (options?: {
node?: Node;
}) => number;
}
declare module '@tiptap/core' {
interface Storage {
characterCount: CharacterCountStorage;
}
}
/**
* This extension allows you to count the characters and words of your document.
* @see https://tiptap.dev/api/extensions/character-count
*/
declare const CharacterCount: Extension<CharacterCountOptions, CharacterCountStorage>;
export { CharacterCount, type CharacterCountOptions, type CharacterCountStorage };
+102
View File
@@ -0,0 +1,102 @@
// src/character-count/character-count.ts
import { Extension } from "@tiptap/core";
import { Plugin, PluginKey } from "@tiptap/pm/state";
var CharacterCount = Extension.create({
name: "characterCount",
addOptions() {
return {
limit: null,
mode: "textSize",
textCounter: (text) => text.length,
wordCounter: (text) => text.split(" ").filter((word) => word !== "").length
};
},
addStorage() {
return {
characters: () => 0,
words: () => 0
};
},
onBeforeCreate() {
this.storage.characters = (options) => {
const node = (options == null ? void 0 : options.node) || this.editor.state.doc;
const mode = (options == null ? void 0 : options.mode) || this.options.mode;
if (mode === "textSize") {
const text = node.textBetween(0, node.content.size, void 0, " ");
return this.options.textCounter(text);
}
return node.nodeSize;
};
this.storage.words = (options) => {
const node = (options == null ? void 0 : options.node) || this.editor.state.doc;
const text = node.textBetween(0, node.content.size, " ", " ");
return this.options.wordCounter(text);
};
},
addProseMirrorPlugins() {
let initialEvaluationDone = false;
return [
new Plugin({
key: new PluginKey("characterCount"),
appendTransaction: (transactions, oldState, newState) => {
if (initialEvaluationDone) {
return;
}
const limit = this.options.limit;
if (limit === null || limit === void 0 || limit === 0) {
initialEvaluationDone = true;
return;
}
const initialContentSize = this.storage.characters({ node: newState.doc });
if (initialContentSize > limit) {
const over = initialContentSize - limit;
const from = 0;
const to = over;
console.warn(
`[CharacterCount] Initial content exceeded limit of ${limit} characters. Content was automatically trimmed.`
);
const tr = newState.tr.deleteRange(from, to);
initialEvaluationDone = true;
return tr;
}
initialEvaluationDone = true;
},
filterTransaction: (transaction, state) => {
const limit = this.options.limit;
if (!transaction.docChanged || limit === 0 || limit === null || limit === void 0) {
return true;
}
const oldSize = this.storage.characters({ node: state.doc });
const newSize = this.storage.characters({ node: transaction.doc });
if (newSize <= limit) {
return true;
}
if (oldSize > limit && newSize > limit && newSize <= oldSize) {
return true;
}
if (oldSize > limit && newSize > limit && newSize > oldSize) {
return false;
}
const isPaste = transaction.getMeta("paste");
if (!isPaste) {
return false;
}
const pos = transaction.selection.$head.pos;
const over = newSize - limit;
const from = pos - over;
const to = pos;
transaction.deleteRange(from, to);
const updatedSize = this.storage.characters({ node: transaction.doc });
if (updatedSize > limit) {
return false;
}
return true;
}
})
];
}
});
export {
CharacterCount
};
//# sourceMappingURL=index.js.map
File diff suppressed because one or more lines are too long
+47
View File
@@ -0,0 +1,47 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/drop-cursor/index.ts
var index_exports = {};
__export(index_exports, {
Dropcursor: () => Dropcursor
});
module.exports = __toCommonJS(index_exports);
// src/drop-cursor/drop-cursor.ts
var import_core = require("@tiptap/core");
var import_dropcursor = require("@tiptap/pm/dropcursor");
var Dropcursor = import_core.Extension.create({
name: "dropCursor",
addOptions() {
return {
color: "currentColor",
width: 1,
class: void 0
};
},
addProseMirrorPlugins() {
return [(0, import_dropcursor.dropCursor)(this.options)];
}
});
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
Dropcursor
});
//# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
{"version":3,"sources":["../../src/drop-cursor/index.ts","../../src/drop-cursor/drop-cursor.ts"],"sourcesContent":["export * from './drop-cursor.js'\n","import { Extension } from '@tiptap/core'\nimport { dropCursor } from '@tiptap/pm/dropcursor'\n\nexport interface DropcursorOptions {\n /**\n * The color of the drop cursor. Use `false` to apply no color and rely only on class.\n * @default 'currentColor'\n * @example 'red'\n */\n color?: string | false\n\n /**\n * The width of the drop cursor\n * @default 1\n * @example 2\n */\n width: number | undefined\n\n /**\n * The class of the drop cursor\n * @default undefined\n * @example 'drop-cursor'\n */\n class: string | undefined\n}\n\n/**\n * This extension allows you to add a drop cursor to your editor.\n * A drop cursor is a line that appears when you drag and drop content\n * in-between nodes.\n * @see https://tiptap.dev/api/extensions/dropcursor\n */\nexport const Dropcursor = Extension.create<DropcursorOptions>({\n name: 'dropCursor',\n\n addOptions() {\n return {\n color: 'currentColor',\n width: 1,\n class: undefined,\n }\n },\n\n addProseMirrorPlugins() {\n return [dropCursor(this.options)]\n },\n})\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,kBAA0B;AAC1B,wBAA2B;AA+BpB,IAAM,aAAa,sBAAU,OAA0B;AAAA,EAC5D,MAAM;AAAA,EAEN,aAAa;AACX,WAAO;AAAA,MACL,OAAO;AAAA,MACP,OAAO;AAAA,MACP,OAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,wBAAwB;AACtB,WAAO,KAAC,8BAAW,KAAK,OAAO,CAAC;AAAA,EAClC;AACF,CAAC;","names":[]}
+31
View File
@@ -0,0 +1,31 @@
import { Extension } from '@tiptap/core';
interface DropcursorOptions {
/**
* The color of the drop cursor. Use `false` to apply no color and rely only on class.
* @default 'currentColor'
* @example 'red'
*/
color?: string | false;
/**
* The width of the drop cursor
* @default 1
* @example 2
*/
width: number | undefined;
/**
* The class of the drop cursor
* @default undefined
* @example 'drop-cursor'
*/
class: string | undefined;
}
/**
* This extension allows you to add a drop cursor to your editor.
* A drop cursor is a line that appears when you drag and drop content
* in-between nodes.
* @see https://tiptap.dev/api/extensions/dropcursor
*/
declare const Dropcursor: Extension<DropcursorOptions, any>;
export { Dropcursor, type DropcursorOptions };
+31
View File
@@ -0,0 +1,31 @@
import { Extension } from '@tiptap/core';
interface DropcursorOptions {
/**
* The color of the drop cursor. Use `false` to apply no color and rely only on class.
* @default 'currentColor'
* @example 'red'
*/
color?: string | false;
/**
* The width of the drop cursor
* @default 1
* @example 2
*/
width: number | undefined;
/**
* The class of the drop cursor
* @default undefined
* @example 'drop-cursor'
*/
class: string | undefined;
}
/**
* This extension allows you to add a drop cursor to your editor.
* A drop cursor is a line that appears when you drag and drop content
* in-between nodes.
* @see https://tiptap.dev/api/extensions/dropcursor
*/
declare const Dropcursor: Extension<DropcursorOptions, any>;
export { Dropcursor, type DropcursorOptions };
+20
View File
@@ -0,0 +1,20 @@
// src/drop-cursor/drop-cursor.ts
import { Extension } from "@tiptap/core";
import { dropCursor } from "@tiptap/pm/dropcursor";
var Dropcursor = Extension.create({
name: "dropCursor",
addOptions() {
return {
color: "currentColor",
width: 1,
class: void 0
};
},
addProseMirrorPlugins() {
return [dropCursor(this.options)];
}
});
export {
Dropcursor
};
//# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
{"version":3,"sources":["../../src/drop-cursor/drop-cursor.ts"],"sourcesContent":["import { Extension } from '@tiptap/core'\nimport { dropCursor } from '@tiptap/pm/dropcursor'\n\nexport interface DropcursorOptions {\n /**\n * The color of the drop cursor. Use `false` to apply no color and rely only on class.\n * @default 'currentColor'\n * @example 'red'\n */\n color?: string | false\n\n /**\n * The width of the drop cursor\n * @default 1\n * @example 2\n */\n width: number | undefined\n\n /**\n * The class of the drop cursor\n * @default undefined\n * @example 'drop-cursor'\n */\n class: string | undefined\n}\n\n/**\n * This extension allows you to add a drop cursor to your editor.\n * A drop cursor is a line that appears when you drag and drop content\n * in-between nodes.\n * @see https://tiptap.dev/api/extensions/dropcursor\n */\nexport const Dropcursor = Extension.create<DropcursorOptions>({\n name: 'dropCursor',\n\n addOptions() {\n return {\n color: 'currentColor',\n width: 1,\n class: undefined,\n }\n },\n\n addProseMirrorPlugins() {\n return [dropCursor(this.options)]\n },\n})\n"],"mappings":";AAAA,SAAS,iBAAiB;AAC1B,SAAS,kBAAkB;AA+BpB,IAAM,aAAa,UAAU,OAA0B;AAAA,EAC5D,MAAM;AAAA,EAEN,aAAa;AACX,WAAO;AAAA,MACL,OAAO;AAAA,MACP,OAAO;AAAA,MACP,OAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,wBAAwB;AACtB,WAAO,CAAC,WAAW,KAAK,OAAO,CAAC;AAAA,EAClC;AACF,CAAC;","names":[]}
+95
View File
@@ -0,0 +1,95 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/focus/index.ts
var index_exports = {};
__export(index_exports, {
Focus: () => Focus
});
module.exports = __toCommonJS(index_exports);
// src/focus/focus.ts
var import_core = require("@tiptap/core");
var import_state = require("@tiptap/pm/state");
var import_view = require("@tiptap/pm/view");
var Focus = import_core.Extension.create({
name: "focus",
addOptions() {
return {
className: "has-focus",
mode: "all"
};
},
addProseMirrorPlugins() {
return [
new import_state.Plugin({
key: new import_state.PluginKey("focus"),
props: {
decorations: ({ doc, selection }) => {
const { isEditable, isFocused } = this.editor;
const { anchor } = selection;
const decorations = [];
if (!isEditable || !isFocused) {
return import_view.DecorationSet.create(doc, []);
}
let maxLevels = 0;
if (this.options.mode === "deepest") {
doc.descendants((node, pos) => {
if (node.isText) {
return;
}
const isCurrent = anchor >= pos && anchor <= pos + node.nodeSize - 1;
if (!isCurrent) {
return false;
}
maxLevels += 1;
});
}
let currentLevel = 0;
doc.descendants((node, pos) => {
if (node.isText) {
return false;
}
const isCurrent = anchor >= pos && anchor <= pos + node.nodeSize - 1;
if (!isCurrent) {
return false;
}
currentLevel += 1;
const outOfScope = this.options.mode === "deepest" && maxLevels - currentLevel > 0 || this.options.mode === "shallowest" && currentLevel > 1;
if (outOfScope) {
return this.options.mode === "deepest";
}
decorations.push(
import_view.Decoration.node(pos, pos + node.nodeSize, {
class: this.options.className
})
);
});
return import_view.DecorationSet.create(doc, decorations);
}
}
})
];
}
});
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
Focus
});
//# sourceMappingURL=index.cjs.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../../src/focus/index.ts","../../src/focus/focus.ts"],"sourcesContent":["export * from './focus.js'\n","import { Extension } from '@tiptap/core'\nimport { Plugin, PluginKey } from '@tiptap/pm/state'\nimport { Decoration, DecorationSet } from '@tiptap/pm/view'\n\nexport interface FocusOptions {\n /**\n * The class name that should be added to the focused node.\n * @default 'has-focus'\n * @example 'is-focused'\n */\n className: string\n\n /**\n * The mode by which the focused node is determined.\n * - All: All nodes are marked as focused.\n * - Deepest: Only the deepest node is marked as focused.\n * - Shallowest: Only the shallowest node is marked as focused.\n *\n * @default 'all'\n * @example 'deepest'\n * @example 'shallowest'\n */\n mode: 'all' | 'deepest' | 'shallowest'\n}\n\n/**\n * This extension allows you to add a class to the focused node.\n * @see https://www.tiptap.dev/api/extensions/focus\n */\nexport const Focus = Extension.create<FocusOptions>({\n name: 'focus',\n\n addOptions() {\n return {\n className: 'has-focus',\n mode: 'all',\n }\n },\n\n addProseMirrorPlugins() {\n return [\n new Plugin({\n key: new PluginKey('focus'),\n props: {\n decorations: ({ doc, selection }) => {\n const { isEditable, isFocused } = this.editor\n const { anchor } = selection\n const decorations: Decoration[] = []\n\n if (!isEditable || !isFocused) {\n return DecorationSet.create(doc, [])\n }\n\n // Maximum Levels\n let maxLevels = 0\n\n if (this.options.mode === 'deepest') {\n doc.descendants((node, pos) => {\n if (node.isText) {\n return\n }\n\n const isCurrent = anchor >= pos && anchor <= pos + node.nodeSize - 1\n\n if (!isCurrent) {\n return false\n }\n\n maxLevels += 1\n })\n }\n\n // Loop through current\n let currentLevel = 0\n\n doc.descendants((node, pos) => {\n if (node.isText) {\n return false\n }\n\n const isCurrent = anchor >= pos && anchor <= pos + node.nodeSize - 1\n\n if (!isCurrent) {\n return false\n }\n\n currentLevel += 1\n\n const outOfScope =\n (this.options.mode === 'deepest' && maxLevels - currentLevel > 0) ||\n (this.options.mode === 'shallowest' && currentLevel > 1)\n\n if (outOfScope) {\n return this.options.mode === 'deepest'\n }\n\n decorations.push(\n Decoration.node(pos, pos + node.nodeSize, {\n class: this.options.className,\n }),\n )\n })\n\n return DecorationSet.create(doc, decorations)\n },\n },\n }),\n ]\n },\n})\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,kBAA0B;AAC1B,mBAAkC;AAClC,kBAA0C;AA2BnC,IAAM,QAAQ,sBAAU,OAAqB;AAAA,EAClD,MAAM;AAAA,EAEN,aAAa;AACX,WAAO;AAAA,MACL,WAAW;AAAA,MACX,MAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,wBAAwB;AACtB,WAAO;AAAA,MACL,IAAI,oBAAO;AAAA,QACT,KAAK,IAAI,uBAAU,OAAO;AAAA,QAC1B,OAAO;AAAA,UACL,aAAa,CAAC,EAAE,KAAK,UAAU,MAAM;AACnC,kBAAM,EAAE,YAAY,UAAU,IAAI,KAAK;AACvC,kBAAM,EAAE,OAAO,IAAI;AACnB,kBAAM,cAA4B,CAAC;AAEnC,gBAAI,CAAC,cAAc,CAAC,WAAW;AAC7B,qBAAO,0BAAc,OAAO,KAAK,CAAC,CAAC;AAAA,YACrC;AAGA,gBAAI,YAAY;AAEhB,gBAAI,KAAK,QAAQ,SAAS,WAAW;AACnC,kBAAI,YAAY,CAAC,MAAM,QAAQ;AAC7B,oBAAI,KAAK,QAAQ;AACf;AAAA,gBACF;AAEA,sBAAM,YAAY,UAAU,OAAO,UAAU,MAAM,KAAK,WAAW;AAEnE,oBAAI,CAAC,WAAW;AACd,yBAAO;AAAA,gBACT;AAEA,6BAAa;AAAA,cACf,CAAC;AAAA,YACH;AAGA,gBAAI,eAAe;AAEnB,gBAAI,YAAY,CAAC,MAAM,QAAQ;AAC7B,kBAAI,KAAK,QAAQ;AACf,uBAAO;AAAA,cACT;AAEA,oBAAM,YAAY,UAAU,OAAO,UAAU,MAAM,KAAK,WAAW;AAEnE,kBAAI,CAAC,WAAW;AACd,uBAAO;AAAA,cACT;AAEA,8BAAgB;AAEhB,oBAAM,aACH,KAAK,QAAQ,SAAS,aAAa,YAAY,eAAe,KAC9D,KAAK,QAAQ,SAAS,gBAAgB,eAAe;AAExD,kBAAI,YAAY;AACd,uBAAO,KAAK,QAAQ,SAAS;AAAA,cAC/B;AAEA,0BAAY;AAAA,gBACV,uBAAW,KAAK,KAAK,MAAM,KAAK,UAAU;AAAA,kBACxC,OAAO,KAAK,QAAQ;AAAA,gBACtB,CAAC;AAAA,cACH;AAAA,YACF,CAAC;AAED,mBAAO,0BAAc,OAAO,KAAK,WAAW;AAAA,UAC9C;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AACF,CAAC;","names":[]}
+28
View File
@@ -0,0 +1,28 @@
import { Extension } from '@tiptap/core';
interface FocusOptions {
/**
* The class name that should be added to the focused node.
* @default 'has-focus'
* @example 'is-focused'
*/
className: string;
/**
* The mode by which the focused node is determined.
* - All: All nodes are marked as focused.
* - Deepest: Only the deepest node is marked as focused.
* - Shallowest: Only the shallowest node is marked as focused.
*
* @default 'all'
* @example 'deepest'
* @example 'shallowest'
*/
mode: 'all' | 'deepest' | 'shallowest';
}
/**
* This extension allows you to add a class to the focused node.
* @see https://www.tiptap.dev/api/extensions/focus
*/
declare const Focus: Extension<FocusOptions, any>;
export { Focus, type FocusOptions };
+28
View File
@@ -0,0 +1,28 @@
import { Extension } from '@tiptap/core';
interface FocusOptions {
/**
* The class name that should be added to the focused node.
* @default 'has-focus'
* @example 'is-focused'
*/
className: string;
/**
* The mode by which the focused node is determined.
* - All: All nodes are marked as focused.
* - Deepest: Only the deepest node is marked as focused.
* - Shallowest: Only the shallowest node is marked as focused.
*
* @default 'all'
* @example 'deepest'
* @example 'shallowest'
*/
mode: 'all' | 'deepest' | 'shallowest';
}
/**
* This extension allows you to add a class to the focused node.
* @see https://www.tiptap.dev/api/extensions/focus
*/
declare const Focus: Extension<FocusOptions, any>;
export { Focus, type FocusOptions };
+68
View File
@@ -0,0 +1,68 @@
// src/focus/focus.ts
import { Extension } from "@tiptap/core";
import { Plugin, PluginKey } from "@tiptap/pm/state";
import { Decoration, DecorationSet } from "@tiptap/pm/view";
var Focus = Extension.create({
name: "focus",
addOptions() {
return {
className: "has-focus",
mode: "all"
};
},
addProseMirrorPlugins() {
return [
new Plugin({
key: new PluginKey("focus"),
props: {
decorations: ({ doc, selection }) => {
const { isEditable, isFocused } = this.editor;
const { anchor } = selection;
const decorations = [];
if (!isEditable || !isFocused) {
return DecorationSet.create(doc, []);
}
let maxLevels = 0;
if (this.options.mode === "deepest") {
doc.descendants((node, pos) => {
if (node.isText) {
return;
}
const isCurrent = anchor >= pos && anchor <= pos + node.nodeSize - 1;
if (!isCurrent) {
return false;
}
maxLevels += 1;
});
}
let currentLevel = 0;
doc.descendants((node, pos) => {
if (node.isText) {
return false;
}
const isCurrent = anchor >= pos && anchor <= pos + node.nodeSize - 1;
if (!isCurrent) {
return false;
}
currentLevel += 1;
const outOfScope = this.options.mode === "deepest" && maxLevels - currentLevel > 0 || this.options.mode === "shallowest" && currentLevel > 1;
if (outOfScope) {
return this.options.mode === "deepest";
}
decorations.push(
Decoration.node(pos, pos + node.nodeSize, {
class: this.options.className
})
);
});
return DecorationSet.create(doc, decorations);
}
}
})
];
}
});
export {
Focus
};
//# sourceMappingURL=index.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../../src/focus/focus.ts"],"sourcesContent":["import { Extension } from '@tiptap/core'\nimport { Plugin, PluginKey } from '@tiptap/pm/state'\nimport { Decoration, DecorationSet } from '@tiptap/pm/view'\n\nexport interface FocusOptions {\n /**\n * The class name that should be added to the focused node.\n * @default 'has-focus'\n * @example 'is-focused'\n */\n className: string\n\n /**\n * The mode by which the focused node is determined.\n * - All: All nodes are marked as focused.\n * - Deepest: Only the deepest node is marked as focused.\n * - Shallowest: Only the shallowest node is marked as focused.\n *\n * @default 'all'\n * @example 'deepest'\n * @example 'shallowest'\n */\n mode: 'all' | 'deepest' | 'shallowest'\n}\n\n/**\n * This extension allows you to add a class to the focused node.\n * @see https://www.tiptap.dev/api/extensions/focus\n */\nexport const Focus = Extension.create<FocusOptions>({\n name: 'focus',\n\n addOptions() {\n return {\n className: 'has-focus',\n mode: 'all',\n }\n },\n\n addProseMirrorPlugins() {\n return [\n new Plugin({\n key: new PluginKey('focus'),\n props: {\n decorations: ({ doc, selection }) => {\n const { isEditable, isFocused } = this.editor\n const { anchor } = selection\n const decorations: Decoration[] = []\n\n if (!isEditable || !isFocused) {\n return DecorationSet.create(doc, [])\n }\n\n // Maximum Levels\n let maxLevels = 0\n\n if (this.options.mode === 'deepest') {\n doc.descendants((node, pos) => {\n if (node.isText) {\n return\n }\n\n const isCurrent = anchor >= pos && anchor <= pos + node.nodeSize - 1\n\n if (!isCurrent) {\n return false\n }\n\n maxLevels += 1\n })\n }\n\n // Loop through current\n let currentLevel = 0\n\n doc.descendants((node, pos) => {\n if (node.isText) {\n return false\n }\n\n const isCurrent = anchor >= pos && anchor <= pos + node.nodeSize - 1\n\n if (!isCurrent) {\n return false\n }\n\n currentLevel += 1\n\n const outOfScope =\n (this.options.mode === 'deepest' && maxLevels - currentLevel > 0) ||\n (this.options.mode === 'shallowest' && currentLevel > 1)\n\n if (outOfScope) {\n return this.options.mode === 'deepest'\n }\n\n decorations.push(\n Decoration.node(pos, pos + node.nodeSize, {\n class: this.options.className,\n }),\n )\n })\n\n return DecorationSet.create(doc, decorations)\n },\n },\n }),\n ]\n },\n})\n"],"mappings":";AAAA,SAAS,iBAAiB;AAC1B,SAAS,QAAQ,iBAAiB;AAClC,SAAS,YAAY,qBAAqB;AA2BnC,IAAM,QAAQ,UAAU,OAAqB;AAAA,EAClD,MAAM;AAAA,EAEN,aAAa;AACX,WAAO;AAAA,MACL,WAAW;AAAA,MACX,MAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,wBAAwB;AACtB,WAAO;AAAA,MACL,IAAI,OAAO;AAAA,QACT,KAAK,IAAI,UAAU,OAAO;AAAA,QAC1B,OAAO;AAAA,UACL,aAAa,CAAC,EAAE,KAAK,UAAU,MAAM;AACnC,kBAAM,EAAE,YAAY,UAAU,IAAI,KAAK;AACvC,kBAAM,EAAE,OAAO,IAAI;AACnB,kBAAM,cAA4B,CAAC;AAEnC,gBAAI,CAAC,cAAc,CAAC,WAAW;AAC7B,qBAAO,cAAc,OAAO,KAAK,CAAC,CAAC;AAAA,YACrC;AAGA,gBAAI,YAAY;AAEhB,gBAAI,KAAK,QAAQ,SAAS,WAAW;AACnC,kBAAI,YAAY,CAAC,MAAM,QAAQ;AAC7B,oBAAI,KAAK,QAAQ;AACf;AAAA,gBACF;AAEA,sBAAM,YAAY,UAAU,OAAO,UAAU,MAAM,KAAK,WAAW;AAEnE,oBAAI,CAAC,WAAW;AACd,yBAAO;AAAA,gBACT;AAEA,6BAAa;AAAA,cACf,CAAC;AAAA,YACH;AAGA,gBAAI,eAAe;AAEnB,gBAAI,YAAY,CAAC,MAAM,QAAQ;AAC7B,kBAAI,KAAK,QAAQ;AACf,uBAAO;AAAA,cACT;AAEA,oBAAM,YAAY,UAAU,OAAO,UAAU,MAAM,KAAK,WAAW;AAEnE,kBAAI,CAAC,WAAW;AACd,uBAAO;AAAA,cACT;AAEA,8BAAgB;AAEhB,oBAAM,aACH,KAAK,QAAQ,SAAS,aAAa,YAAY,eAAe,KAC9D,KAAK,QAAQ,SAAS,gBAAgB,eAAe;AAExD,kBAAI,YAAY;AACd,uBAAO,KAAK,QAAQ,SAAS;AAAA,cAC/B;AAEA,0BAAY;AAAA,gBACV,WAAW,KAAK,KAAK,MAAM,KAAK,UAAU;AAAA,kBACxC,OAAO,KAAK,QAAQ;AAAA,gBACtB,CAAC;AAAA,cACH;AAAA,YACF,CAAC;AAED,mBAAO,cAAc,OAAO,KAAK,WAAW;AAAA,UAC9C;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AACF,CAAC;","names":[]}
+51
View File
@@ -0,0 +1,51 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/gap-cursor/index.ts
var index_exports = {};
__export(index_exports, {
Gapcursor: () => Gapcursor
});
module.exports = __toCommonJS(index_exports);
// src/gap-cursor/gap-cursor.ts
var import_core = require("@tiptap/core");
var import_gapcursor = require("@tiptap/pm/gapcursor");
var Gapcursor = import_core.Extension.create({
name: "gapCursor",
addProseMirrorPlugins() {
return [(0, import_gapcursor.gapCursor)()];
},
extendNodeSchema(extension) {
var _a;
const context = {
name: extension.name,
options: extension.options,
storage: extension.storage
};
return {
allowGapCursor: (_a = (0, import_core.callOrReturn)((0, import_core.getExtensionField)(extension, "allowGapCursor", context))) != null ? _a : null
};
}
});
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
Gapcursor
});
//# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
{"version":3,"sources":["../../src/gap-cursor/index.ts","../../src/gap-cursor/gap-cursor.ts"],"sourcesContent":["export * from './gap-cursor.js'\n","import type { ParentConfig } from '@tiptap/core'\nimport { callOrReturn, Extension, getExtensionField } from '@tiptap/core'\nimport { gapCursor } from '@tiptap/pm/gapcursor'\n\ndeclare module '@tiptap/core' {\n interface NodeConfig<Options, Storage> {\n /**\n * A function to determine whether the gap cursor is allowed at the current position. Must return `true` or `false`.\n * @default null\n */\n allowGapCursor?:\n | boolean\n | null\n | ((this: {\n name: string\n options: Options\n storage: Storage\n parent: ParentConfig<NodeConfig<Options>>['allowGapCursor']\n }) => boolean | null)\n }\n}\n\n/**\n * This extension allows you to add a gap cursor to your editor.\n * A gap cursor is a cursor that appears when you click on a place\n * where no content is present, for example inbetween nodes.\n * @see https://tiptap.dev/api/extensions/gapcursor\n */\nexport const Gapcursor = Extension.create({\n name: 'gapCursor',\n\n addProseMirrorPlugins() {\n return [gapCursor()]\n },\n\n extendNodeSchema(extension) {\n const context = {\n name: extension.name,\n options: extension.options,\n storage: extension.storage,\n }\n\n return {\n allowGapCursor: callOrReturn(getExtensionField(extension, 'allowGapCursor', context)) ?? null,\n }\n },\n})\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACCA,kBAA2D;AAC3D,uBAA0B;AA0BnB,IAAM,YAAY,sBAAU,OAAO;AAAA,EACxC,MAAM;AAAA,EAEN,wBAAwB;AACtB,WAAO,KAAC,4BAAU,CAAC;AAAA,EACrB;AAAA,EAEA,iBAAiB,WAAW;AAnC9B;AAoCI,UAAM,UAAU;AAAA,MACd,MAAM,UAAU;AAAA,MAChB,SAAS,UAAU;AAAA,MACnB,SAAS,UAAU;AAAA,IACrB;AAEA,WAAO;AAAA,MACL,iBAAgB,uCAAa,+BAAkB,WAAW,kBAAkB,OAAO,CAAC,MAApE,YAAyE;AAAA,IAC3F;AAAA,EACF;AACF,CAAC;","names":[]}
+25
View File
@@ -0,0 +1,25 @@
import { ParentConfig, Extension } from '@tiptap/core';
declare module '@tiptap/core' {
interface NodeConfig<Options, Storage> {
/**
* A function to determine whether the gap cursor is allowed at the current position. Must return `true` or `false`.
* @default null
*/
allowGapCursor?: boolean | null | ((this: {
name: string;
options: Options;
storage: Storage;
parent: ParentConfig<NodeConfig<Options>>['allowGapCursor'];
}) => boolean | null);
}
}
/**
* This extension allows you to add a gap cursor to your editor.
* A gap cursor is a cursor that appears when you click on a place
* where no content is present, for example inbetween nodes.
* @see https://tiptap.dev/api/extensions/gapcursor
*/
declare const Gapcursor: Extension<any, any>;
export { Gapcursor };
+25
View File
@@ -0,0 +1,25 @@
import { ParentConfig, Extension } from '@tiptap/core';
declare module '@tiptap/core' {
interface NodeConfig<Options, Storage> {
/**
* A function to determine whether the gap cursor is allowed at the current position. Must return `true` or `false`.
* @default null
*/
allowGapCursor?: boolean | null | ((this: {
name: string;
options: Options;
storage: Storage;
parent: ParentConfig<NodeConfig<Options>>['allowGapCursor'];
}) => boolean | null);
}
}
/**
* This extension allows you to add a gap cursor to your editor.
* A gap cursor is a cursor that appears when you click on a place
* where no content is present, for example inbetween nodes.
* @see https://tiptap.dev/api/extensions/gapcursor
*/
declare const Gapcursor: Extension<any, any>;
export { Gapcursor };
+24
View File
@@ -0,0 +1,24 @@
// src/gap-cursor/gap-cursor.ts
import { callOrReturn, Extension, getExtensionField } from "@tiptap/core";
import { gapCursor } from "@tiptap/pm/gapcursor";
var Gapcursor = Extension.create({
name: "gapCursor",
addProseMirrorPlugins() {
return [gapCursor()];
},
extendNodeSchema(extension) {
var _a;
const context = {
name: extension.name,
options: extension.options,
storage: extension.storage
};
return {
allowGapCursor: (_a = callOrReturn(getExtensionField(extension, "allowGapCursor", context))) != null ? _a : null
};
}
});
export {
Gapcursor
};
//# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
{"version":3,"sources":["../../src/gap-cursor/gap-cursor.ts"],"sourcesContent":["import type { ParentConfig } from '@tiptap/core'\nimport { callOrReturn, Extension, getExtensionField } from '@tiptap/core'\nimport { gapCursor } from '@tiptap/pm/gapcursor'\n\ndeclare module '@tiptap/core' {\n interface NodeConfig<Options, Storage> {\n /**\n * A function to determine whether the gap cursor is allowed at the current position. Must return `true` or `false`.\n * @default null\n */\n allowGapCursor?:\n | boolean\n | null\n | ((this: {\n name: string\n options: Options\n storage: Storage\n parent: ParentConfig<NodeConfig<Options>>['allowGapCursor']\n }) => boolean | null)\n }\n}\n\n/**\n * This extension allows you to add a gap cursor to your editor.\n * A gap cursor is a cursor that appears when you click on a place\n * where no content is present, for example inbetween nodes.\n * @see https://tiptap.dev/api/extensions/gapcursor\n */\nexport const Gapcursor = Extension.create({\n name: 'gapCursor',\n\n addProseMirrorPlugins() {\n return [gapCursor()]\n },\n\n extendNodeSchema(extension) {\n const context = {\n name: extension.name,\n options: extension.options,\n storage: extension.storage,\n }\n\n return {\n allowGapCursor: callOrReturn(getExtensionField(extension, 'allowGapCursor', context)) ?? null,\n }\n },\n})\n"],"mappings":";AACA,SAAS,cAAc,WAAW,yBAAyB;AAC3D,SAAS,iBAAiB;AA0BnB,IAAM,YAAY,UAAU,OAAO;AAAA,EACxC,MAAM;AAAA,EAEN,wBAAwB;AACtB,WAAO,CAAC,UAAU,CAAC;AAAA,EACrB;AAAA,EAEA,iBAAiB,WAAW;AAnC9B;AAoCI,UAAM,UAAU;AAAA,MACd,MAAM,UAAU;AAAA,MAChB,SAAS,UAAU;AAAA,MACnB,SAAS,UAAU;AAAA,IACrB;AAEA,WAAO;AAAA,MACL,iBAAgB,kBAAa,kBAAkB,WAAW,kBAAkB,OAAO,CAAC,MAApE,YAAyE;AAAA,IAC3F;AAAA,EACF;AACF,CAAC;","names":[]}
+434
View File
@@ -0,0 +1,434 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var index_exports = {};
__export(index_exports, {
CharacterCount: () => CharacterCount,
Dropcursor: () => Dropcursor,
Focus: () => Focus,
Gapcursor: () => Gapcursor,
Placeholder: () => Placeholder,
Selection: () => Selection,
TrailingNode: () => TrailingNode,
UndoRedo: () => UndoRedo,
preparePlaceholderAttribute: () => preparePlaceholderAttribute
});
module.exports = __toCommonJS(index_exports);
// src/character-count/character-count.ts
var import_core = require("@tiptap/core");
var import_state = require("@tiptap/pm/state");
var CharacterCount = import_core.Extension.create({
name: "characterCount",
addOptions() {
return {
limit: null,
mode: "textSize",
textCounter: (text) => text.length,
wordCounter: (text) => text.split(" ").filter((word) => word !== "").length
};
},
addStorage() {
return {
characters: () => 0,
words: () => 0
};
},
onBeforeCreate() {
this.storage.characters = (options) => {
const node = (options == null ? void 0 : options.node) || this.editor.state.doc;
const mode = (options == null ? void 0 : options.mode) || this.options.mode;
if (mode === "textSize") {
const text = node.textBetween(0, node.content.size, void 0, " ");
return this.options.textCounter(text);
}
return node.nodeSize;
};
this.storage.words = (options) => {
const node = (options == null ? void 0 : options.node) || this.editor.state.doc;
const text = node.textBetween(0, node.content.size, " ", " ");
return this.options.wordCounter(text);
};
},
addProseMirrorPlugins() {
let initialEvaluationDone = false;
return [
new import_state.Plugin({
key: new import_state.PluginKey("characterCount"),
appendTransaction: (transactions, oldState, newState) => {
if (initialEvaluationDone) {
return;
}
const limit = this.options.limit;
if (limit === null || limit === void 0 || limit === 0) {
initialEvaluationDone = true;
return;
}
const initialContentSize = this.storage.characters({ node: newState.doc });
if (initialContentSize > limit) {
const over = initialContentSize - limit;
const from = 0;
const to = over;
console.warn(
`[CharacterCount] Initial content exceeded limit of ${limit} characters. Content was automatically trimmed.`
);
const tr = newState.tr.deleteRange(from, to);
initialEvaluationDone = true;
return tr;
}
initialEvaluationDone = true;
},
filterTransaction: (transaction, state) => {
const limit = this.options.limit;
if (!transaction.docChanged || limit === 0 || limit === null || limit === void 0) {
return true;
}
const oldSize = this.storage.characters({ node: state.doc });
const newSize = this.storage.characters({ node: transaction.doc });
if (newSize <= limit) {
return true;
}
if (oldSize > limit && newSize > limit && newSize <= oldSize) {
return true;
}
if (oldSize > limit && newSize > limit && newSize > oldSize) {
return false;
}
const isPaste = transaction.getMeta("paste");
if (!isPaste) {
return false;
}
const pos = transaction.selection.$head.pos;
const over = newSize - limit;
const from = pos - over;
const to = pos;
transaction.deleteRange(from, to);
const updatedSize = this.storage.characters({ node: transaction.doc });
if (updatedSize > limit) {
return false;
}
return true;
}
})
];
}
});
// src/drop-cursor/drop-cursor.ts
var import_core2 = require("@tiptap/core");
var import_dropcursor = require("@tiptap/pm/dropcursor");
var Dropcursor = import_core2.Extension.create({
name: "dropCursor",
addOptions() {
return {
color: "currentColor",
width: 1,
class: void 0
};
},
addProseMirrorPlugins() {
return [(0, import_dropcursor.dropCursor)(this.options)];
}
});
// src/focus/focus.ts
var import_core3 = require("@tiptap/core");
var import_state2 = require("@tiptap/pm/state");
var import_view = require("@tiptap/pm/view");
var Focus = import_core3.Extension.create({
name: "focus",
addOptions() {
return {
className: "has-focus",
mode: "all"
};
},
addProseMirrorPlugins() {
return [
new import_state2.Plugin({
key: new import_state2.PluginKey("focus"),
props: {
decorations: ({ doc, selection }) => {
const { isEditable, isFocused } = this.editor;
const { anchor } = selection;
const decorations = [];
if (!isEditable || !isFocused) {
return import_view.DecorationSet.create(doc, []);
}
let maxLevels = 0;
if (this.options.mode === "deepest") {
doc.descendants((node, pos) => {
if (node.isText) {
return;
}
const isCurrent = anchor >= pos && anchor <= pos + node.nodeSize - 1;
if (!isCurrent) {
return false;
}
maxLevels += 1;
});
}
let currentLevel = 0;
doc.descendants((node, pos) => {
if (node.isText) {
return false;
}
const isCurrent = anchor >= pos && anchor <= pos + node.nodeSize - 1;
if (!isCurrent) {
return false;
}
currentLevel += 1;
const outOfScope = this.options.mode === "deepest" && maxLevels - currentLevel > 0 || this.options.mode === "shallowest" && currentLevel > 1;
if (outOfScope) {
return this.options.mode === "deepest";
}
decorations.push(
import_view.Decoration.node(pos, pos + node.nodeSize, {
class: this.options.className
})
);
});
return import_view.DecorationSet.create(doc, decorations);
}
}
})
];
}
});
// src/gap-cursor/gap-cursor.ts
var import_core4 = require("@tiptap/core");
var import_gapcursor = require("@tiptap/pm/gapcursor");
var Gapcursor = import_core4.Extension.create({
name: "gapCursor",
addProseMirrorPlugins() {
return [(0, import_gapcursor.gapCursor)()];
},
extendNodeSchema(extension) {
var _a;
const context = {
name: extension.name,
options: extension.options,
storage: extension.storage
};
return {
allowGapCursor: (_a = (0, import_core4.callOrReturn)((0, import_core4.getExtensionField)(extension, "allowGapCursor", context))) != null ? _a : null
};
}
});
// src/placeholder/placeholder.ts
var import_core5 = require("@tiptap/core");
var import_state3 = require("@tiptap/pm/state");
var import_view2 = require("@tiptap/pm/view");
var DEFAULT_DATA_ATTRIBUTE = "placeholder";
function preparePlaceholderAttribute(attr) {
return attr.replace(/\s+/g, "-").replace(/[^a-zA-Z0-9-]/g, "").replace(/^[0-9-]+/, "").replace(/^-+/, "").toLowerCase();
}
var Placeholder = import_core5.Extension.create({
name: "placeholder",
addOptions() {
return {
emptyEditorClass: "is-editor-empty",
emptyNodeClass: "is-empty",
dataAttribute: DEFAULT_DATA_ATTRIBUTE,
placeholder: "Write something \u2026",
showOnlyWhenEditable: true,
showOnlyCurrent: true,
includeChildren: false
};
},
addProseMirrorPlugins() {
const dataAttribute = this.options.dataAttribute ? `data-${preparePlaceholderAttribute(this.options.dataAttribute)}` : `data-${DEFAULT_DATA_ATTRIBUTE}`;
return [
new import_state3.Plugin({
key: new import_state3.PluginKey("placeholder"),
props: {
decorations: ({ doc, selection }) => {
const active = this.editor.isEditable || !this.options.showOnlyWhenEditable;
const { anchor } = selection;
const decorations = [];
if (!active) {
return null;
}
const isEmptyDoc = this.editor.isEmpty;
doc.descendants((node, pos) => {
const hasAnchor = anchor >= pos && anchor <= pos + node.nodeSize;
const isEmpty = !node.isLeaf && (0, import_core5.isNodeEmpty)(node);
if ((hasAnchor || !this.options.showOnlyCurrent) && isEmpty) {
const classes = [this.options.emptyNodeClass];
if (isEmptyDoc) {
classes.push(this.options.emptyEditorClass);
}
const decoration = import_view2.Decoration.node(pos, pos + node.nodeSize, {
class: classes.join(" "),
[dataAttribute]: typeof this.options.placeholder === "function" ? this.options.placeholder({
editor: this.editor,
node,
pos,
hasAnchor
}) : this.options.placeholder
});
decorations.push(decoration);
}
return this.options.includeChildren;
});
return import_view2.DecorationSet.create(doc, decorations);
}
}
})
];
}
});
// src/selection/selection.ts
var import_core6 = require("@tiptap/core");
var import_state4 = require("@tiptap/pm/state");
var import_view3 = require("@tiptap/pm/view");
var Selection = import_core6.Extension.create({
name: "selection",
addOptions() {
return {
className: "selection"
};
},
addProseMirrorPlugins() {
const { editor, options } = this;
return [
new import_state4.Plugin({
key: new import_state4.PluginKey("selection"),
props: {
decorations(state) {
if (state.selection.empty || editor.isFocused || !editor.isEditable || (0, import_core6.isNodeSelection)(state.selection) || editor.view.dragging) {
return null;
}
return import_view3.DecorationSet.create(state.doc, [
import_view3.Decoration.inline(state.selection.from, state.selection.to, {
class: options.className
})
]);
}
}
})
];
}
});
// src/trailing-node/trailing-node.ts
var import_core7 = require("@tiptap/core");
var import_state5 = require("@tiptap/pm/state");
function nodeEqualsType({ types, node }) {
return node && Array.isArray(types) && types.includes(node.type) || (node == null ? void 0 : node.type) === types;
}
var TrailingNode = import_core7.Extension.create({
name: "trailingNode",
addOptions() {
return {
node: void 0,
notAfter: []
};
},
addProseMirrorPlugins() {
var _a;
const plugin = new import_state5.PluginKey(this.name);
const defaultNode = this.options.node || ((_a = this.editor.schema.topNodeType.contentMatch.defaultType) == null ? void 0 : _a.name) || "paragraph";
const disabledNodes = Object.entries(this.editor.schema.nodes).map(([, value]) => value).filter((node) => (this.options.notAfter || []).concat(defaultNode).includes(node.name));
return [
new import_state5.Plugin({
key: plugin,
appendTransaction: (_, __, state) => {
const { doc, tr, schema } = state;
const shouldInsertNodeAtEnd = plugin.getState(state);
const endPosition = doc.content.size;
const type = schema.nodes[defaultNode];
if (!shouldInsertNodeAtEnd) {
return;
}
return tr.insert(endPosition, type.create());
},
state: {
init: (_, state) => {
const lastNode = state.tr.doc.lastChild;
return !nodeEqualsType({ node: lastNode, types: disabledNodes });
},
apply: (tr, value) => {
if (!tr.docChanged) {
return value;
}
if (tr.getMeta("__uniqueIDTransaction")) {
return value;
}
const lastNode = tr.doc.lastChild;
return !nodeEqualsType({ node: lastNode, types: disabledNodes });
}
}
})
];
}
});
// src/undo-redo/undo-redo.ts
var import_core8 = require("@tiptap/core");
var import_history = require("@tiptap/pm/history");
var UndoRedo = import_core8.Extension.create({
name: "undoRedo",
addOptions() {
return {
depth: 100,
newGroupDelay: 500
};
},
addCommands() {
return {
undo: () => ({ state, dispatch }) => {
return (0, import_history.undo)(state, dispatch);
},
redo: () => ({ state, dispatch }) => {
return (0, import_history.redo)(state, dispatch);
}
};
},
addProseMirrorPlugins() {
return [(0, import_history.history)(this.options)];
},
addKeyboardShortcuts() {
return {
"Mod-z": () => this.editor.commands.undo(),
"Shift-Mod-z": () => this.editor.commands.redo(),
"Mod-y": () => this.editor.commands.redo(),
// Russian keyboard layouts
"Mod-\u044F": () => this.editor.commands.undo(),
"Shift-Mod-\u044F": () => this.editor.commands.redo()
};
}
});
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
CharacterCount,
Dropcursor,
Focus,
Gapcursor,
Placeholder,
Selection,
TrailingNode,
UndoRedo,
preparePlaceholderAttribute
});
//# sourceMappingURL=index.cjs.map
File diff suppressed because one or more lines are too long
+284
View File
@@ -0,0 +1,284 @@
import { Extension, ParentConfig, Editor } from '@tiptap/core';
import { Node } from '@tiptap/pm/model';
interface CharacterCountOptions {
/**
* The maximum number of characters that should be allowed. Defaults to `0`.
* @default null
* @example 180
*/
limit: number | null | undefined;
/**
* The mode by which the size is calculated. If set to `textSize`, the textContent of the document is used.
* If set to `nodeSize`, the nodeSize of the document is used.
* @default 'textSize'
* @example 'textSize'
*/
mode: 'textSize' | 'nodeSize';
/**
* The text counter function to use. Defaults to a simple character count.
* @default (text) => text.length
* @example (text) => [...new Intl.Segmenter().segment(text)].length
*/
textCounter: (text: string) => number;
/**
* The word counter function to use. Defaults to a simple word count.
* @default (text) => text.split(' ').filter(word => word !== '').length
* @example (text) => text.split(/\s+/).filter(word => word !== '').length
*/
wordCounter: (text: string) => number;
}
interface CharacterCountStorage {
/**
* Get the number of characters for the current document.
* @param options The options for the character count. (optional)
* @param options.node The node to get the characters from. Defaults to the current document.
* @param options.mode The mode by which the size is calculated. If set to `textSize`, the textContent of the document is used.
*/
characters: (options?: {
node?: Node;
mode?: 'textSize' | 'nodeSize';
}) => number;
/**
* Get the number of words for the current document.
* @param options The options for the character count. (optional)
* @param options.node The node to get the words from. Defaults to the current document.
*/
words: (options?: {
node?: Node;
}) => number;
}
declare module '@tiptap/core' {
interface Storage {
characterCount: CharacterCountStorage;
}
}
/**
* This extension allows you to count the characters and words of your document.
* @see https://tiptap.dev/api/extensions/character-count
*/
declare const CharacterCount: Extension<CharacterCountOptions, CharacterCountStorage>;
interface DropcursorOptions {
/**
* The color of the drop cursor. Use `false` to apply no color and rely only on class.
* @default 'currentColor'
* @example 'red'
*/
color?: string | false;
/**
* The width of the drop cursor
* @default 1
* @example 2
*/
width: number | undefined;
/**
* The class of the drop cursor
* @default undefined
* @example 'drop-cursor'
*/
class: string | undefined;
}
/**
* This extension allows you to add a drop cursor to your editor.
* A drop cursor is a line that appears when you drag and drop content
* in-between nodes.
* @see https://tiptap.dev/api/extensions/dropcursor
*/
declare const Dropcursor: Extension<DropcursorOptions, any>;
interface FocusOptions {
/**
* The class name that should be added to the focused node.
* @default 'has-focus'
* @example 'is-focused'
*/
className: string;
/**
* The mode by which the focused node is determined.
* - All: All nodes are marked as focused.
* - Deepest: Only the deepest node is marked as focused.
* - Shallowest: Only the shallowest node is marked as focused.
*
* @default 'all'
* @example 'deepest'
* @example 'shallowest'
*/
mode: 'all' | 'deepest' | 'shallowest';
}
/**
* This extension allows you to add a class to the focused node.
* @see https://www.tiptap.dev/api/extensions/focus
*/
declare const Focus: Extension<FocusOptions, any>;
declare module '@tiptap/core' {
interface NodeConfig<Options, Storage> {
/**
* A function to determine whether the gap cursor is allowed at the current position. Must return `true` or `false`.
* @default null
*/
allowGapCursor?: boolean | null | ((this: {
name: string;
options: Options;
storage: Storage;
parent: ParentConfig<NodeConfig<Options>>['allowGapCursor'];
}) => boolean | null);
}
}
/**
* This extension allows you to add a gap cursor to your editor.
* A gap cursor is a cursor that appears when you click on a place
* where no content is present, for example inbetween nodes.
* @see https://tiptap.dev/api/extensions/gapcursor
*/
declare const Gapcursor: Extension<any, any>;
/**
* Prepares the placeholder attribute by ensuring it is properly formatted.
* @param attr - The placeholder attribute string.
* @returns The prepared placeholder attribute string.
*/
declare function preparePlaceholderAttribute(attr: string): string;
interface PlaceholderOptions {
/**
* **The class name for the empty editor**
* @default 'is-editor-empty'
*/
emptyEditorClass: string;
/**
* **The class name for empty nodes**
* @default 'is-empty'
*/
emptyNodeClass: string;
/**
* **The data-attribute used for the placeholder label**
* Will be prepended with `data-` and converted to kebab-case and cleaned of special characters.
* @default 'placeholder'
*/
dataAttribute: string;
/**
* **The placeholder content**
*
* You can use a function to return a dynamic placeholder or a string.
* @default 'Write something …'
*/
placeholder: ((PlaceholderProps: {
editor: Editor;
node: Node;
pos: number;
hasAnchor: boolean;
}) => string) | string;
/**
* **Checks if the placeholder should be only shown when the editor is editable.**
*
* If true, the placeholder will only be shown when the editor is editable.
* If false, the placeholder will always be shown.
* @default true
*/
showOnlyWhenEditable: boolean;
/**
* **Checks if the placeholder should be only shown when the current node is empty.**
*
* If true, the placeholder will only be shown when the current node is empty.
* If false, the placeholder will be shown when any node is empty.
* @default true
*/
showOnlyCurrent: boolean;
/**
* **Controls if the placeholder should be shown for all descendents.**
*
* If true, the placeholder will be shown for all descendents.
* If false, the placeholder will only be shown for the current node.
* @default false
*/
includeChildren: boolean;
}
/**
* This extension allows you to add a placeholder to your editor.
* A placeholder is a text that appears when the editor or a node is empty.
* @see https://www.tiptap.dev/api/extensions/placeholder
*/
declare const Placeholder: Extension<PlaceholderOptions, any>;
type SelectionOptions = {
/**
* The class name that should be added to the selected text.
* @default 'selection'
* @example 'is-selected'
*/
className: string;
};
/**
* This extension allows you to add a class to the selected text.
* @see https://www.tiptap.dev/api/extensions/selection
*/
declare const Selection: Extension<SelectionOptions, any>;
/**
* Extension based on:
* - https://github.com/ueberdosis/tiptap/blob/v1/packages/tiptap-extensions/src/extensions/TrailingNode.js
* - https://github.com/remirror/remirror/blob/e0f1bec4a1e8073ce8f5500d62193e52321155b9/packages/prosemirror-trailing-node/src/trailing-node-plugin.ts
*/
interface TrailingNodeOptions {
/**
* The node type that should be inserted at the end of the document.
* @note the node will always be added to the `notAfter` lists to
* prevent an infinite loop.
* @default undefined
*/
node?: string;
/**
* The node types after which the trailing node should not be inserted.
* @default ['paragraph']
*/
notAfter?: string | string[];
}
/**
* This extension allows you to add an extra node at the end of the document.
* @see https://www.tiptap.dev/api/extensions/trailing-node
*/
declare const TrailingNode: Extension<TrailingNodeOptions, any>;
interface UndoRedoOptions {
/**
* The amount of history events that are collected before the oldest events are discarded.
* @default 100
* @example 50
*/
depth: number;
/**
* The delay (in milliseconds) between changes after which a new group should be started.
* @default 500
* @example 1000
*/
newGroupDelay: number;
}
declare module '@tiptap/core' {
interface Commands<ReturnType> {
undoRedo: {
/**
* Undo recent changes
* @example editor.commands.undo()
*/
undo: () => ReturnType;
/**
* Reapply reverted changes
* @example editor.commands.redo()
*/
redo: () => ReturnType;
};
}
}
/**
* This extension allows you to undo and redo recent changes.
* @see https://www.tiptap.dev/api/extensions/undo-redo
*
* **Important**: If the `@tiptap/extension-collaboration` package is used, make sure to remove
* the `undo-redo` extension, as it is not compatible with the `collaboration` extension.
*
* `@tiptap/extension-collaboration` uses its own history implementation.
*/
declare const UndoRedo: Extension<UndoRedoOptions, any>;
export { CharacterCount, type CharacterCountOptions, type CharacterCountStorage, Dropcursor, type DropcursorOptions, Focus, type FocusOptions, Gapcursor, Placeholder, type PlaceholderOptions, Selection, type SelectionOptions, TrailingNode, type TrailingNodeOptions, UndoRedo, type UndoRedoOptions, preparePlaceholderAttribute };
+284
View File
@@ -0,0 +1,284 @@
import { Extension, ParentConfig, Editor } from '@tiptap/core';
import { Node } from '@tiptap/pm/model';
interface CharacterCountOptions {
/**
* The maximum number of characters that should be allowed. Defaults to `0`.
* @default null
* @example 180
*/
limit: number | null | undefined;
/**
* The mode by which the size is calculated. If set to `textSize`, the textContent of the document is used.
* If set to `nodeSize`, the nodeSize of the document is used.
* @default 'textSize'
* @example 'textSize'
*/
mode: 'textSize' | 'nodeSize';
/**
* The text counter function to use. Defaults to a simple character count.
* @default (text) => text.length
* @example (text) => [...new Intl.Segmenter().segment(text)].length
*/
textCounter: (text: string) => number;
/**
* The word counter function to use. Defaults to a simple word count.
* @default (text) => text.split(' ').filter(word => word !== '').length
* @example (text) => text.split(/\s+/).filter(word => word !== '').length
*/
wordCounter: (text: string) => number;
}
interface CharacterCountStorage {
/**
* Get the number of characters for the current document.
* @param options The options for the character count. (optional)
* @param options.node The node to get the characters from. Defaults to the current document.
* @param options.mode The mode by which the size is calculated. If set to `textSize`, the textContent of the document is used.
*/
characters: (options?: {
node?: Node;
mode?: 'textSize' | 'nodeSize';
}) => number;
/**
* Get the number of words for the current document.
* @param options The options for the character count. (optional)
* @param options.node The node to get the words from. Defaults to the current document.
*/
words: (options?: {
node?: Node;
}) => number;
}
declare module '@tiptap/core' {
interface Storage {
characterCount: CharacterCountStorage;
}
}
/**
* This extension allows you to count the characters and words of your document.
* @see https://tiptap.dev/api/extensions/character-count
*/
declare const CharacterCount: Extension<CharacterCountOptions, CharacterCountStorage>;
interface DropcursorOptions {
/**
* The color of the drop cursor. Use `false` to apply no color and rely only on class.
* @default 'currentColor'
* @example 'red'
*/
color?: string | false;
/**
* The width of the drop cursor
* @default 1
* @example 2
*/
width: number | undefined;
/**
* The class of the drop cursor
* @default undefined
* @example 'drop-cursor'
*/
class: string | undefined;
}
/**
* This extension allows you to add a drop cursor to your editor.
* A drop cursor is a line that appears when you drag and drop content
* in-between nodes.
* @see https://tiptap.dev/api/extensions/dropcursor
*/
declare const Dropcursor: Extension<DropcursorOptions, any>;
interface FocusOptions {
/**
* The class name that should be added to the focused node.
* @default 'has-focus'
* @example 'is-focused'
*/
className: string;
/**
* The mode by which the focused node is determined.
* - All: All nodes are marked as focused.
* - Deepest: Only the deepest node is marked as focused.
* - Shallowest: Only the shallowest node is marked as focused.
*
* @default 'all'
* @example 'deepest'
* @example 'shallowest'
*/
mode: 'all' | 'deepest' | 'shallowest';
}
/**
* This extension allows you to add a class to the focused node.
* @see https://www.tiptap.dev/api/extensions/focus
*/
declare const Focus: Extension<FocusOptions, any>;
declare module '@tiptap/core' {
interface NodeConfig<Options, Storage> {
/**
* A function to determine whether the gap cursor is allowed at the current position. Must return `true` or `false`.
* @default null
*/
allowGapCursor?: boolean | null | ((this: {
name: string;
options: Options;
storage: Storage;
parent: ParentConfig<NodeConfig<Options>>['allowGapCursor'];
}) => boolean | null);
}
}
/**
* This extension allows you to add a gap cursor to your editor.
* A gap cursor is a cursor that appears when you click on a place
* where no content is present, for example inbetween nodes.
* @see https://tiptap.dev/api/extensions/gapcursor
*/
declare const Gapcursor: Extension<any, any>;
/**
* Prepares the placeholder attribute by ensuring it is properly formatted.
* @param attr - The placeholder attribute string.
* @returns The prepared placeholder attribute string.
*/
declare function preparePlaceholderAttribute(attr: string): string;
interface PlaceholderOptions {
/**
* **The class name for the empty editor**
* @default 'is-editor-empty'
*/
emptyEditorClass: string;
/**
* **The class name for empty nodes**
* @default 'is-empty'
*/
emptyNodeClass: string;
/**
* **The data-attribute used for the placeholder label**
* Will be prepended with `data-` and converted to kebab-case and cleaned of special characters.
* @default 'placeholder'
*/
dataAttribute: string;
/**
* **The placeholder content**
*
* You can use a function to return a dynamic placeholder or a string.
* @default 'Write something …'
*/
placeholder: ((PlaceholderProps: {
editor: Editor;
node: Node;
pos: number;
hasAnchor: boolean;
}) => string) | string;
/**
* **Checks if the placeholder should be only shown when the editor is editable.**
*
* If true, the placeholder will only be shown when the editor is editable.
* If false, the placeholder will always be shown.
* @default true
*/
showOnlyWhenEditable: boolean;
/**
* **Checks if the placeholder should be only shown when the current node is empty.**
*
* If true, the placeholder will only be shown when the current node is empty.
* If false, the placeholder will be shown when any node is empty.
* @default true
*/
showOnlyCurrent: boolean;
/**
* **Controls if the placeholder should be shown for all descendents.**
*
* If true, the placeholder will be shown for all descendents.
* If false, the placeholder will only be shown for the current node.
* @default false
*/
includeChildren: boolean;
}
/**
* This extension allows you to add a placeholder to your editor.
* A placeholder is a text that appears when the editor or a node is empty.
* @see https://www.tiptap.dev/api/extensions/placeholder
*/
declare const Placeholder: Extension<PlaceholderOptions, any>;
type SelectionOptions = {
/**
* The class name that should be added to the selected text.
* @default 'selection'
* @example 'is-selected'
*/
className: string;
};
/**
* This extension allows you to add a class to the selected text.
* @see https://www.tiptap.dev/api/extensions/selection
*/
declare const Selection: Extension<SelectionOptions, any>;
/**
* Extension based on:
* - https://github.com/ueberdosis/tiptap/blob/v1/packages/tiptap-extensions/src/extensions/TrailingNode.js
* - https://github.com/remirror/remirror/blob/e0f1bec4a1e8073ce8f5500d62193e52321155b9/packages/prosemirror-trailing-node/src/trailing-node-plugin.ts
*/
interface TrailingNodeOptions {
/**
* The node type that should be inserted at the end of the document.
* @note the node will always be added to the `notAfter` lists to
* prevent an infinite loop.
* @default undefined
*/
node?: string;
/**
* The node types after which the trailing node should not be inserted.
* @default ['paragraph']
*/
notAfter?: string | string[];
}
/**
* This extension allows you to add an extra node at the end of the document.
* @see https://www.tiptap.dev/api/extensions/trailing-node
*/
declare const TrailingNode: Extension<TrailingNodeOptions, any>;
interface UndoRedoOptions {
/**
* The amount of history events that are collected before the oldest events are discarded.
* @default 100
* @example 50
*/
depth: number;
/**
* The delay (in milliseconds) between changes after which a new group should be started.
* @default 500
* @example 1000
*/
newGroupDelay: number;
}
declare module '@tiptap/core' {
interface Commands<ReturnType> {
undoRedo: {
/**
* Undo recent changes
* @example editor.commands.undo()
*/
undo: () => ReturnType;
/**
* Reapply reverted changes
* @example editor.commands.redo()
*/
redo: () => ReturnType;
};
}
}
/**
* This extension allows you to undo and redo recent changes.
* @see https://www.tiptap.dev/api/extensions/undo-redo
*
* **Important**: If the `@tiptap/extension-collaboration` package is used, make sure to remove
* the `undo-redo` extension, as it is not compatible with the `collaboration` extension.
*
* `@tiptap/extension-collaboration` uses its own history implementation.
*/
declare const UndoRedo: Extension<UndoRedoOptions, any>;
export { CharacterCount, type CharacterCountOptions, type CharacterCountStorage, Dropcursor, type DropcursorOptions, Focus, type FocusOptions, Gapcursor, Placeholder, type PlaceholderOptions, Selection, type SelectionOptions, TrailingNode, type TrailingNodeOptions, UndoRedo, type UndoRedoOptions, preparePlaceholderAttribute };
+399
View File
@@ -0,0 +1,399 @@
// src/character-count/character-count.ts
import { Extension } from "@tiptap/core";
import { Plugin, PluginKey } from "@tiptap/pm/state";
var CharacterCount = Extension.create({
name: "characterCount",
addOptions() {
return {
limit: null,
mode: "textSize",
textCounter: (text) => text.length,
wordCounter: (text) => text.split(" ").filter((word) => word !== "").length
};
},
addStorage() {
return {
characters: () => 0,
words: () => 0
};
},
onBeforeCreate() {
this.storage.characters = (options) => {
const node = (options == null ? void 0 : options.node) || this.editor.state.doc;
const mode = (options == null ? void 0 : options.mode) || this.options.mode;
if (mode === "textSize") {
const text = node.textBetween(0, node.content.size, void 0, " ");
return this.options.textCounter(text);
}
return node.nodeSize;
};
this.storage.words = (options) => {
const node = (options == null ? void 0 : options.node) || this.editor.state.doc;
const text = node.textBetween(0, node.content.size, " ", " ");
return this.options.wordCounter(text);
};
},
addProseMirrorPlugins() {
let initialEvaluationDone = false;
return [
new Plugin({
key: new PluginKey("characterCount"),
appendTransaction: (transactions, oldState, newState) => {
if (initialEvaluationDone) {
return;
}
const limit = this.options.limit;
if (limit === null || limit === void 0 || limit === 0) {
initialEvaluationDone = true;
return;
}
const initialContentSize = this.storage.characters({ node: newState.doc });
if (initialContentSize > limit) {
const over = initialContentSize - limit;
const from = 0;
const to = over;
console.warn(
`[CharacterCount] Initial content exceeded limit of ${limit} characters. Content was automatically trimmed.`
);
const tr = newState.tr.deleteRange(from, to);
initialEvaluationDone = true;
return tr;
}
initialEvaluationDone = true;
},
filterTransaction: (transaction, state) => {
const limit = this.options.limit;
if (!transaction.docChanged || limit === 0 || limit === null || limit === void 0) {
return true;
}
const oldSize = this.storage.characters({ node: state.doc });
const newSize = this.storage.characters({ node: transaction.doc });
if (newSize <= limit) {
return true;
}
if (oldSize > limit && newSize > limit && newSize <= oldSize) {
return true;
}
if (oldSize > limit && newSize > limit && newSize > oldSize) {
return false;
}
const isPaste = transaction.getMeta("paste");
if (!isPaste) {
return false;
}
const pos = transaction.selection.$head.pos;
const over = newSize - limit;
const from = pos - over;
const to = pos;
transaction.deleteRange(from, to);
const updatedSize = this.storage.characters({ node: transaction.doc });
if (updatedSize > limit) {
return false;
}
return true;
}
})
];
}
});
// src/drop-cursor/drop-cursor.ts
import { Extension as Extension2 } from "@tiptap/core";
import { dropCursor } from "@tiptap/pm/dropcursor";
var Dropcursor = Extension2.create({
name: "dropCursor",
addOptions() {
return {
color: "currentColor",
width: 1,
class: void 0
};
},
addProseMirrorPlugins() {
return [dropCursor(this.options)];
}
});
// src/focus/focus.ts
import { Extension as Extension3 } from "@tiptap/core";
import { Plugin as Plugin2, PluginKey as PluginKey2 } from "@tiptap/pm/state";
import { Decoration, DecorationSet } from "@tiptap/pm/view";
var Focus = Extension3.create({
name: "focus",
addOptions() {
return {
className: "has-focus",
mode: "all"
};
},
addProseMirrorPlugins() {
return [
new Plugin2({
key: new PluginKey2("focus"),
props: {
decorations: ({ doc, selection }) => {
const { isEditable, isFocused } = this.editor;
const { anchor } = selection;
const decorations = [];
if (!isEditable || !isFocused) {
return DecorationSet.create(doc, []);
}
let maxLevels = 0;
if (this.options.mode === "deepest") {
doc.descendants((node, pos) => {
if (node.isText) {
return;
}
const isCurrent = anchor >= pos && anchor <= pos + node.nodeSize - 1;
if (!isCurrent) {
return false;
}
maxLevels += 1;
});
}
let currentLevel = 0;
doc.descendants((node, pos) => {
if (node.isText) {
return false;
}
const isCurrent = anchor >= pos && anchor <= pos + node.nodeSize - 1;
if (!isCurrent) {
return false;
}
currentLevel += 1;
const outOfScope = this.options.mode === "deepest" && maxLevels - currentLevel > 0 || this.options.mode === "shallowest" && currentLevel > 1;
if (outOfScope) {
return this.options.mode === "deepest";
}
decorations.push(
Decoration.node(pos, pos + node.nodeSize, {
class: this.options.className
})
);
});
return DecorationSet.create(doc, decorations);
}
}
})
];
}
});
// src/gap-cursor/gap-cursor.ts
import { callOrReturn, Extension as Extension4, getExtensionField } from "@tiptap/core";
import { gapCursor } from "@tiptap/pm/gapcursor";
var Gapcursor = Extension4.create({
name: "gapCursor",
addProseMirrorPlugins() {
return [gapCursor()];
},
extendNodeSchema(extension) {
var _a;
const context = {
name: extension.name,
options: extension.options,
storage: extension.storage
};
return {
allowGapCursor: (_a = callOrReturn(getExtensionField(extension, "allowGapCursor", context))) != null ? _a : null
};
}
});
// src/placeholder/placeholder.ts
import { Extension as Extension5, isNodeEmpty } from "@tiptap/core";
import { Plugin as Plugin3, PluginKey as PluginKey3 } from "@tiptap/pm/state";
import { Decoration as Decoration2, DecorationSet as DecorationSet2 } from "@tiptap/pm/view";
var DEFAULT_DATA_ATTRIBUTE = "placeholder";
function preparePlaceholderAttribute(attr) {
return attr.replace(/\s+/g, "-").replace(/[^a-zA-Z0-9-]/g, "").replace(/^[0-9-]+/, "").replace(/^-+/, "").toLowerCase();
}
var Placeholder = Extension5.create({
name: "placeholder",
addOptions() {
return {
emptyEditorClass: "is-editor-empty",
emptyNodeClass: "is-empty",
dataAttribute: DEFAULT_DATA_ATTRIBUTE,
placeholder: "Write something \u2026",
showOnlyWhenEditable: true,
showOnlyCurrent: true,
includeChildren: false
};
},
addProseMirrorPlugins() {
const dataAttribute = this.options.dataAttribute ? `data-${preparePlaceholderAttribute(this.options.dataAttribute)}` : `data-${DEFAULT_DATA_ATTRIBUTE}`;
return [
new Plugin3({
key: new PluginKey3("placeholder"),
props: {
decorations: ({ doc, selection }) => {
const active = this.editor.isEditable || !this.options.showOnlyWhenEditable;
const { anchor } = selection;
const decorations = [];
if (!active) {
return null;
}
const isEmptyDoc = this.editor.isEmpty;
doc.descendants((node, pos) => {
const hasAnchor = anchor >= pos && anchor <= pos + node.nodeSize;
const isEmpty = !node.isLeaf && isNodeEmpty(node);
if ((hasAnchor || !this.options.showOnlyCurrent) && isEmpty) {
const classes = [this.options.emptyNodeClass];
if (isEmptyDoc) {
classes.push(this.options.emptyEditorClass);
}
const decoration = Decoration2.node(pos, pos + node.nodeSize, {
class: classes.join(" "),
[dataAttribute]: typeof this.options.placeholder === "function" ? this.options.placeholder({
editor: this.editor,
node,
pos,
hasAnchor
}) : this.options.placeholder
});
decorations.push(decoration);
}
return this.options.includeChildren;
});
return DecorationSet2.create(doc, decorations);
}
}
})
];
}
});
// src/selection/selection.ts
import { Extension as Extension6, isNodeSelection } from "@tiptap/core";
import { Plugin as Plugin4, PluginKey as PluginKey4 } from "@tiptap/pm/state";
import { Decoration as Decoration3, DecorationSet as DecorationSet3 } from "@tiptap/pm/view";
var Selection = Extension6.create({
name: "selection",
addOptions() {
return {
className: "selection"
};
},
addProseMirrorPlugins() {
const { editor, options } = this;
return [
new Plugin4({
key: new PluginKey4("selection"),
props: {
decorations(state) {
if (state.selection.empty || editor.isFocused || !editor.isEditable || isNodeSelection(state.selection) || editor.view.dragging) {
return null;
}
return DecorationSet3.create(state.doc, [
Decoration3.inline(state.selection.from, state.selection.to, {
class: options.className
})
]);
}
}
})
];
}
});
// src/trailing-node/trailing-node.ts
import { Extension as Extension7 } from "@tiptap/core";
import { Plugin as Plugin5, PluginKey as PluginKey5 } from "@tiptap/pm/state";
function nodeEqualsType({ types, node }) {
return node && Array.isArray(types) && types.includes(node.type) || (node == null ? void 0 : node.type) === types;
}
var TrailingNode = Extension7.create({
name: "trailingNode",
addOptions() {
return {
node: void 0,
notAfter: []
};
},
addProseMirrorPlugins() {
var _a;
const plugin = new PluginKey5(this.name);
const defaultNode = this.options.node || ((_a = this.editor.schema.topNodeType.contentMatch.defaultType) == null ? void 0 : _a.name) || "paragraph";
const disabledNodes = Object.entries(this.editor.schema.nodes).map(([, value]) => value).filter((node) => (this.options.notAfter || []).concat(defaultNode).includes(node.name));
return [
new Plugin5({
key: plugin,
appendTransaction: (_, __, state) => {
const { doc, tr, schema } = state;
const shouldInsertNodeAtEnd = plugin.getState(state);
const endPosition = doc.content.size;
const type = schema.nodes[defaultNode];
if (!shouldInsertNodeAtEnd) {
return;
}
return tr.insert(endPosition, type.create());
},
state: {
init: (_, state) => {
const lastNode = state.tr.doc.lastChild;
return !nodeEqualsType({ node: lastNode, types: disabledNodes });
},
apply: (tr, value) => {
if (!tr.docChanged) {
return value;
}
if (tr.getMeta("__uniqueIDTransaction")) {
return value;
}
const lastNode = tr.doc.lastChild;
return !nodeEqualsType({ node: lastNode, types: disabledNodes });
}
}
})
];
}
});
// src/undo-redo/undo-redo.ts
import { Extension as Extension8 } from "@tiptap/core";
import { history, redo, undo } from "@tiptap/pm/history";
var UndoRedo = Extension8.create({
name: "undoRedo",
addOptions() {
return {
depth: 100,
newGroupDelay: 500
};
},
addCommands() {
return {
undo: () => ({ state, dispatch }) => {
return undo(state, dispatch);
},
redo: () => ({ state, dispatch }) => {
return redo(state, dispatch);
}
};
},
addProseMirrorPlugins() {
return [history(this.options)];
},
addKeyboardShortcuts() {
return {
"Mod-z": () => this.editor.commands.undo(),
"Shift-Mod-z": () => this.editor.commands.redo(),
"Mod-y": () => this.editor.commands.redo(),
// Russian keyboard layouts
"Mod-\u044F": () => this.editor.commands.undo(),
"Shift-Mod-\u044F": () => this.editor.commands.redo()
};
}
});
export {
CharacterCount,
Dropcursor,
Focus,
Gapcursor,
Placeholder,
Selection,
TrailingNode,
UndoRedo,
preparePlaceholderAttribute
};
//# sourceMappingURL=index.js.map
File diff suppressed because one or more lines are too long
+96
View File
@@ -0,0 +1,96 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/placeholder/index.ts
var index_exports = {};
__export(index_exports, {
Placeholder: () => Placeholder,
preparePlaceholderAttribute: () => preparePlaceholderAttribute
});
module.exports = __toCommonJS(index_exports);
// src/placeholder/placeholder.ts
var import_core = require("@tiptap/core");
var import_state = require("@tiptap/pm/state");
var import_view = require("@tiptap/pm/view");
var DEFAULT_DATA_ATTRIBUTE = "placeholder";
function preparePlaceholderAttribute(attr) {
return attr.replace(/\s+/g, "-").replace(/[^a-zA-Z0-9-]/g, "").replace(/^[0-9-]+/, "").replace(/^-+/, "").toLowerCase();
}
var Placeholder = import_core.Extension.create({
name: "placeholder",
addOptions() {
return {
emptyEditorClass: "is-editor-empty",
emptyNodeClass: "is-empty",
dataAttribute: DEFAULT_DATA_ATTRIBUTE,
placeholder: "Write something \u2026",
showOnlyWhenEditable: true,
showOnlyCurrent: true,
includeChildren: false
};
},
addProseMirrorPlugins() {
const dataAttribute = this.options.dataAttribute ? `data-${preparePlaceholderAttribute(this.options.dataAttribute)}` : `data-${DEFAULT_DATA_ATTRIBUTE}`;
return [
new import_state.Plugin({
key: new import_state.PluginKey("placeholder"),
props: {
decorations: ({ doc, selection }) => {
const active = this.editor.isEditable || !this.options.showOnlyWhenEditable;
const { anchor } = selection;
const decorations = [];
if (!active) {
return null;
}
const isEmptyDoc = this.editor.isEmpty;
doc.descendants((node, pos) => {
const hasAnchor = anchor >= pos && anchor <= pos + node.nodeSize;
const isEmpty = !node.isLeaf && (0, import_core.isNodeEmpty)(node);
if ((hasAnchor || !this.options.showOnlyCurrent) && isEmpty) {
const classes = [this.options.emptyNodeClass];
if (isEmptyDoc) {
classes.push(this.options.emptyEditorClass);
}
const decoration = import_view.Decoration.node(pos, pos + node.nodeSize, {
class: classes.join(" "),
[dataAttribute]: typeof this.options.placeholder === "function" ? this.options.placeholder({
editor: this.editor,
node,
pos,
hasAnchor
}) : this.options.placeholder
});
decorations.push(decoration);
}
return this.options.includeChildren;
});
return import_view.DecorationSet.create(doc, decorations);
}
}
})
];
}
});
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
Placeholder,
preparePlaceholderAttribute
});
//# sourceMappingURL=index.cjs.map
File diff suppressed because one or more lines are too long
+71
View File
@@ -0,0 +1,71 @@
import { Editor, Extension } from '@tiptap/core';
import { Node } from '@tiptap/pm/model';
/**
* Prepares the placeholder attribute by ensuring it is properly formatted.
* @param attr - The placeholder attribute string.
* @returns The prepared placeholder attribute string.
*/
declare function preparePlaceholderAttribute(attr: string): string;
interface PlaceholderOptions {
/**
* **The class name for the empty editor**
* @default 'is-editor-empty'
*/
emptyEditorClass: string;
/**
* **The class name for empty nodes**
* @default 'is-empty'
*/
emptyNodeClass: string;
/**
* **The data-attribute used for the placeholder label**
* Will be prepended with `data-` and converted to kebab-case and cleaned of special characters.
* @default 'placeholder'
*/
dataAttribute: string;
/**
* **The placeholder content**
*
* You can use a function to return a dynamic placeholder or a string.
* @default 'Write something …'
*/
placeholder: ((PlaceholderProps: {
editor: Editor;
node: Node;
pos: number;
hasAnchor: boolean;
}) => string) | string;
/**
* **Checks if the placeholder should be only shown when the editor is editable.**
*
* If true, the placeholder will only be shown when the editor is editable.
* If false, the placeholder will always be shown.
* @default true
*/
showOnlyWhenEditable: boolean;
/**
* **Checks if the placeholder should be only shown when the current node is empty.**
*
* If true, the placeholder will only be shown when the current node is empty.
* If false, the placeholder will be shown when any node is empty.
* @default true
*/
showOnlyCurrent: boolean;
/**
* **Controls if the placeholder should be shown for all descendents.**
*
* If true, the placeholder will be shown for all descendents.
* If false, the placeholder will only be shown for the current node.
* @default false
*/
includeChildren: boolean;
}
/**
* This extension allows you to add a placeholder to your editor.
* A placeholder is a text that appears when the editor or a node is empty.
* @see https://www.tiptap.dev/api/extensions/placeholder
*/
declare const Placeholder: Extension<PlaceholderOptions, any>;
export { Placeholder, type PlaceholderOptions, preparePlaceholderAttribute };
+71
View File
@@ -0,0 +1,71 @@
import { Editor, Extension } from '@tiptap/core';
import { Node } from '@tiptap/pm/model';
/**
* Prepares the placeholder attribute by ensuring it is properly formatted.
* @param attr - The placeholder attribute string.
* @returns The prepared placeholder attribute string.
*/
declare function preparePlaceholderAttribute(attr: string): string;
interface PlaceholderOptions {
/**
* **The class name for the empty editor**
* @default 'is-editor-empty'
*/
emptyEditorClass: string;
/**
* **The class name for empty nodes**
* @default 'is-empty'
*/
emptyNodeClass: string;
/**
* **The data-attribute used for the placeholder label**
* Will be prepended with `data-` and converted to kebab-case and cleaned of special characters.
* @default 'placeholder'
*/
dataAttribute: string;
/**
* **The placeholder content**
*
* You can use a function to return a dynamic placeholder or a string.
* @default 'Write something …'
*/
placeholder: ((PlaceholderProps: {
editor: Editor;
node: Node;
pos: number;
hasAnchor: boolean;
}) => string) | string;
/**
* **Checks if the placeholder should be only shown when the editor is editable.**
*
* If true, the placeholder will only be shown when the editor is editable.
* If false, the placeholder will always be shown.
* @default true
*/
showOnlyWhenEditable: boolean;
/**
* **Checks if the placeholder should be only shown when the current node is empty.**
*
* If true, the placeholder will only be shown when the current node is empty.
* If false, the placeholder will be shown when any node is empty.
* @default true
*/
showOnlyCurrent: boolean;
/**
* **Controls if the placeholder should be shown for all descendents.**
*
* If true, the placeholder will be shown for all descendents.
* If false, the placeholder will only be shown for the current node.
* @default false
*/
includeChildren: boolean;
}
/**
* This extension allows you to add a placeholder to your editor.
* A placeholder is a text that appears when the editor or a node is empty.
* @see https://www.tiptap.dev/api/extensions/placeholder
*/
declare const Placeholder: Extension<PlaceholderOptions, any>;
export { Placeholder, type PlaceholderOptions, preparePlaceholderAttribute };
+68
View File
@@ -0,0 +1,68 @@
// src/placeholder/placeholder.ts
import { Extension, isNodeEmpty } from "@tiptap/core";
import { Plugin, PluginKey } from "@tiptap/pm/state";
import { Decoration, DecorationSet } from "@tiptap/pm/view";
var DEFAULT_DATA_ATTRIBUTE = "placeholder";
function preparePlaceholderAttribute(attr) {
return attr.replace(/\s+/g, "-").replace(/[^a-zA-Z0-9-]/g, "").replace(/^[0-9-]+/, "").replace(/^-+/, "").toLowerCase();
}
var Placeholder = Extension.create({
name: "placeholder",
addOptions() {
return {
emptyEditorClass: "is-editor-empty",
emptyNodeClass: "is-empty",
dataAttribute: DEFAULT_DATA_ATTRIBUTE,
placeholder: "Write something \u2026",
showOnlyWhenEditable: true,
showOnlyCurrent: true,
includeChildren: false
};
},
addProseMirrorPlugins() {
const dataAttribute = this.options.dataAttribute ? `data-${preparePlaceholderAttribute(this.options.dataAttribute)}` : `data-${DEFAULT_DATA_ATTRIBUTE}`;
return [
new Plugin({
key: new PluginKey("placeholder"),
props: {
decorations: ({ doc, selection }) => {
const active = this.editor.isEditable || !this.options.showOnlyWhenEditable;
const { anchor } = selection;
const decorations = [];
if (!active) {
return null;
}
const isEmptyDoc = this.editor.isEmpty;
doc.descendants((node, pos) => {
const hasAnchor = anchor >= pos && anchor <= pos + node.nodeSize;
const isEmpty = !node.isLeaf && isNodeEmpty(node);
if ((hasAnchor || !this.options.showOnlyCurrent) && isEmpty) {
const classes = [this.options.emptyNodeClass];
if (isEmptyDoc) {
classes.push(this.options.emptyEditorClass);
}
const decoration = Decoration.node(pos, pos + node.nodeSize, {
class: classes.join(" "),
[dataAttribute]: typeof this.options.placeholder === "function" ? this.options.placeholder({
editor: this.editor,
node,
pos,
hasAnchor
}) : this.options.placeholder
});
decorations.push(decoration);
}
return this.options.includeChildren;
});
return DecorationSet.create(doc, decorations);
}
}
})
];
}
});
export {
Placeholder,
preparePlaceholderAttribute
};
//# sourceMappingURL=index.js.map
File diff suppressed because one or more lines are too long
+63
View File
@@ -0,0 +1,63 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/selection/index.ts
var index_exports = {};
__export(index_exports, {
Selection: () => Selection
});
module.exports = __toCommonJS(index_exports);
// src/selection/selection.ts
var import_core = require("@tiptap/core");
var import_state = require("@tiptap/pm/state");
var import_view = require("@tiptap/pm/view");
var Selection = import_core.Extension.create({
name: "selection",
addOptions() {
return {
className: "selection"
};
},
addProseMirrorPlugins() {
const { editor, options } = this;
return [
new import_state.Plugin({
key: new import_state.PluginKey("selection"),
props: {
decorations(state) {
if (state.selection.empty || editor.isFocused || !editor.isEditable || (0, import_core.isNodeSelection)(state.selection) || editor.view.dragging) {
return null;
}
return import_view.DecorationSet.create(state.doc, [
import_view.Decoration.inline(state.selection.from, state.selection.to, {
class: options.className
})
]);
}
}
})
];
}
});
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
Selection
});
//# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
{"version":3,"sources":["../../src/selection/index.ts","../../src/selection/selection.ts"],"sourcesContent":["export * from './selection.js'\n","import { Extension, isNodeSelection } from '@tiptap/core'\nimport { Plugin, PluginKey } from '@tiptap/pm/state'\nimport { Decoration, DecorationSet } from '@tiptap/pm/view'\n\nexport type SelectionOptions = {\n /**\n * The class name that should be added to the selected text.\n * @default 'selection'\n * @example 'is-selected'\n */\n className: string\n}\n\n/**\n * This extension allows you to add a class to the selected text.\n * @see https://www.tiptap.dev/api/extensions/selection\n */\nexport const Selection = Extension.create<SelectionOptions>({\n name: 'selection',\n\n addOptions() {\n return {\n className: 'selection',\n }\n },\n\n addProseMirrorPlugins() {\n const { editor, options } = this\n\n return [\n new Plugin({\n key: new PluginKey('selection'),\n props: {\n decorations(state) {\n if (\n state.selection.empty ||\n editor.isFocused ||\n !editor.isEditable ||\n isNodeSelection(state.selection) ||\n editor.view.dragging\n ) {\n return null\n }\n\n return DecorationSet.create(state.doc, [\n Decoration.inline(state.selection.from, state.selection.to, {\n class: options.className,\n }),\n ])\n },\n },\n }),\n ]\n },\n})\n\nexport default Selection\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,kBAA2C;AAC3C,mBAAkC;AAClC,kBAA0C;AAenC,IAAM,YAAY,sBAAU,OAAyB;AAAA,EAC1D,MAAM;AAAA,EAEN,aAAa;AACX,WAAO;AAAA,MACL,WAAW;AAAA,IACb;AAAA,EACF;AAAA,EAEA,wBAAwB;AACtB,UAAM,EAAE,QAAQ,QAAQ,IAAI;AAE5B,WAAO;AAAA,MACL,IAAI,oBAAO;AAAA,QACT,KAAK,IAAI,uBAAU,WAAW;AAAA,QAC9B,OAAO;AAAA,UACL,YAAY,OAAO;AACjB,gBACE,MAAM,UAAU,SAChB,OAAO,aACP,CAAC,OAAO,kBACR,6BAAgB,MAAM,SAAS,KAC/B,OAAO,KAAK,UACZ;AACA,qBAAO;AAAA,YACT;AAEA,mBAAO,0BAAc,OAAO,MAAM,KAAK;AAAA,cACrC,uBAAW,OAAO,MAAM,UAAU,MAAM,MAAM,UAAU,IAAI;AAAA,gBAC1D,OAAO,QAAQ;AAAA,cACjB,CAAC;AAAA,YACH,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AACF,CAAC;","names":[]}
+17
View File
@@ -0,0 +1,17 @@
import { Extension } from '@tiptap/core';
type SelectionOptions = {
/**
* The class name that should be added to the selected text.
* @default 'selection'
* @example 'is-selected'
*/
className: string;
};
/**
* This extension allows you to add a class to the selected text.
* @see https://www.tiptap.dev/api/extensions/selection
*/
declare const Selection: Extension<SelectionOptions, any>;
export { Selection, type SelectionOptions };
+17
View File
@@ -0,0 +1,17 @@
import { Extension } from '@tiptap/core';
type SelectionOptions = {
/**
* The class name that should be added to the selected text.
* @default 'selection'
* @example 'is-selected'
*/
className: string;
};
/**
* This extension allows you to add a class to the selected text.
* @see https://www.tiptap.dev/api/extensions/selection
*/
declare const Selection: Extension<SelectionOptions, any>;
export { Selection, type SelectionOptions };
+36
View File
@@ -0,0 +1,36 @@
// src/selection/selection.ts
import { Extension, isNodeSelection } from "@tiptap/core";
import { Plugin, PluginKey } from "@tiptap/pm/state";
import { Decoration, DecorationSet } from "@tiptap/pm/view";
var Selection = Extension.create({
name: "selection",
addOptions() {
return {
className: "selection"
};
},
addProseMirrorPlugins() {
const { editor, options } = this;
return [
new Plugin({
key: new PluginKey("selection"),
props: {
decorations(state) {
if (state.selection.empty || editor.isFocused || !editor.isEditable || isNodeSelection(state.selection) || editor.view.dragging) {
return null;
}
return DecorationSet.create(state.doc, [
Decoration.inline(state.selection.from, state.selection.to, {
class: options.className
})
]);
}
}
})
];
}
});
export {
Selection
};
//# sourceMappingURL=index.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../../src/selection/selection.ts"],"sourcesContent":["import { Extension, isNodeSelection } from '@tiptap/core'\nimport { Plugin, PluginKey } from '@tiptap/pm/state'\nimport { Decoration, DecorationSet } from '@tiptap/pm/view'\n\nexport type SelectionOptions = {\n /**\n * The class name that should be added to the selected text.\n * @default 'selection'\n * @example 'is-selected'\n */\n className: string\n}\n\n/**\n * This extension allows you to add a class to the selected text.\n * @see https://www.tiptap.dev/api/extensions/selection\n */\nexport const Selection = Extension.create<SelectionOptions>({\n name: 'selection',\n\n addOptions() {\n return {\n className: 'selection',\n }\n },\n\n addProseMirrorPlugins() {\n const { editor, options } = this\n\n return [\n new Plugin({\n key: new PluginKey('selection'),\n props: {\n decorations(state) {\n if (\n state.selection.empty ||\n editor.isFocused ||\n !editor.isEditable ||\n isNodeSelection(state.selection) ||\n editor.view.dragging\n ) {\n return null\n }\n\n return DecorationSet.create(state.doc, [\n Decoration.inline(state.selection.from, state.selection.to, {\n class: options.className,\n }),\n ])\n },\n },\n }),\n ]\n },\n})\n\nexport default Selection\n"],"mappings":";AAAA,SAAS,WAAW,uBAAuB;AAC3C,SAAS,QAAQ,iBAAiB;AAClC,SAAS,YAAY,qBAAqB;AAenC,IAAM,YAAY,UAAU,OAAyB;AAAA,EAC1D,MAAM;AAAA,EAEN,aAAa;AACX,WAAO;AAAA,MACL,WAAW;AAAA,IACb;AAAA,EACF;AAAA,EAEA,wBAAwB;AACtB,UAAM,EAAE,QAAQ,QAAQ,IAAI;AAE5B,WAAO;AAAA,MACL,IAAI,OAAO;AAAA,QACT,KAAK,IAAI,UAAU,WAAW;AAAA,QAC9B,OAAO;AAAA,UACL,YAAY,OAAO;AACjB,gBACE,MAAM,UAAU,SAChB,OAAO,aACP,CAAC,OAAO,cACR,gBAAgB,MAAM,SAAS,KAC/B,OAAO,KAAK,UACZ;AACA,qBAAO;AAAA,YACT;AAEA,mBAAO,cAAc,OAAO,MAAM,KAAK;AAAA,cACrC,WAAW,OAAO,MAAM,UAAU,MAAM,MAAM,UAAU,IAAI;AAAA,gBAC1D,OAAO,QAAQ;AAAA,cACjB,CAAC;AAAA,YACH,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AACF,CAAC;","names":[]}
+83
View File
@@ -0,0 +1,83 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/trailing-node/index.ts
var index_exports = {};
__export(index_exports, {
TrailingNode: () => TrailingNode
});
module.exports = __toCommonJS(index_exports);
// src/trailing-node/trailing-node.ts
var import_core = require("@tiptap/core");
var import_state = require("@tiptap/pm/state");
function nodeEqualsType({ types, node }) {
return node && Array.isArray(types) && types.includes(node.type) || (node == null ? void 0 : node.type) === types;
}
var TrailingNode = import_core.Extension.create({
name: "trailingNode",
addOptions() {
return {
node: void 0,
notAfter: []
};
},
addProseMirrorPlugins() {
var _a;
const plugin = new import_state.PluginKey(this.name);
const defaultNode = this.options.node || ((_a = this.editor.schema.topNodeType.contentMatch.defaultType) == null ? void 0 : _a.name) || "paragraph";
const disabledNodes = Object.entries(this.editor.schema.nodes).map(([, value]) => value).filter((node) => (this.options.notAfter || []).concat(defaultNode).includes(node.name));
return [
new import_state.Plugin({
key: plugin,
appendTransaction: (_, __, state) => {
const { doc, tr, schema } = state;
const shouldInsertNodeAtEnd = plugin.getState(state);
const endPosition = doc.content.size;
const type = schema.nodes[defaultNode];
if (!shouldInsertNodeAtEnd) {
return;
}
return tr.insert(endPosition, type.create());
},
state: {
init: (_, state) => {
const lastNode = state.tr.doc.lastChild;
return !nodeEqualsType({ node: lastNode, types: disabledNodes });
},
apply: (tr, value) => {
if (!tr.docChanged) {
return value;
}
if (tr.getMeta("__uniqueIDTransaction")) {
return value;
}
const lastNode = tr.doc.lastChild;
return !nodeEqualsType({ node: lastNode, types: disabledNodes });
}
}
})
];
}
});
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
TrailingNode
});
//# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
{"version":3,"sources":["../../src/trailing-node/index.ts","../../src/trailing-node/trailing-node.ts"],"sourcesContent":["export * from './trailing-node.js'\n","import { Extension } from '@tiptap/core'\nimport type { Node, NodeType } from '@tiptap/pm/model'\nimport { Plugin, PluginKey } from '@tiptap/pm/state'\n\nfunction nodeEqualsType({ types, node }: { types: NodeType | NodeType[]; node: Node | null | undefined }) {\n return (node && Array.isArray(types) && types.includes(node.type)) || node?.type === types\n}\n\n/**\n * Extension based on:\n * - https://github.com/ueberdosis/tiptap/blob/v1/packages/tiptap-extensions/src/extensions/TrailingNode.js\n * - https://github.com/remirror/remirror/blob/e0f1bec4a1e8073ce8f5500d62193e52321155b9/packages/prosemirror-trailing-node/src/trailing-node-plugin.ts\n */\n\nexport interface TrailingNodeOptions {\n /**\n * The node type that should be inserted at the end of the document.\n * @note the node will always be added to the `notAfter` lists to\n * prevent an infinite loop.\n * @default undefined\n */\n node?: string\n /**\n * The node types after which the trailing node should not be inserted.\n * @default ['paragraph']\n */\n notAfter?: string | string[]\n}\n\n/**\n * This extension allows you to add an extra node at the end of the document.\n * @see https://www.tiptap.dev/api/extensions/trailing-node\n */\nexport const TrailingNode = Extension.create<TrailingNodeOptions>({\n name: 'trailingNode',\n\n addOptions() {\n return {\n node: undefined,\n notAfter: [],\n }\n },\n\n addProseMirrorPlugins() {\n const plugin = new PluginKey(this.name)\n const defaultNode =\n this.options.node || this.editor.schema.topNodeType.contentMatch.defaultType?.name || 'paragraph'\n\n const disabledNodes = Object.entries(this.editor.schema.nodes)\n .map(([, value]) => value)\n .filter(node => (this.options.notAfter || []).concat(defaultNode).includes(node.name))\n\n return [\n new Plugin({\n key: plugin,\n appendTransaction: (_, __, state) => {\n const { doc, tr, schema } = state\n const shouldInsertNodeAtEnd = plugin.getState(state)\n const endPosition = doc.content.size\n const type = schema.nodes[defaultNode]\n\n if (!shouldInsertNodeAtEnd) {\n return\n }\n\n return tr.insert(endPosition, type.create())\n },\n state: {\n init: (_, state) => {\n const lastNode = state.tr.doc.lastChild\n\n return !nodeEqualsType({ node: lastNode, types: disabledNodes })\n },\n apply: (tr, value) => {\n if (!tr.docChanged) {\n return value\n }\n\n // Ignore transactions from UniqueID extension to prevent infinite loops\n // when UniqueID adds IDs to newly inserted trailing nodes\n if (tr.getMeta('__uniqueIDTransaction')) {\n return value\n }\n\n const lastNode = tr.doc.lastChild\n\n return !nodeEqualsType({ node: lastNode, types: disabledNodes })\n },\n },\n }),\n ]\n },\n})\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,kBAA0B;AAE1B,mBAAkC;AAElC,SAAS,eAAe,EAAE,OAAO,KAAK,GAAoE;AACxG,SAAQ,QAAQ,MAAM,QAAQ,KAAK,KAAK,MAAM,SAAS,KAAK,IAAI,MAAM,6BAAM,UAAS;AACvF;AA2BO,IAAM,eAAe,sBAAU,OAA4B;AAAA,EAChE,MAAM;AAAA,EAEN,aAAa;AACX,WAAO;AAAA,MACL,MAAM;AAAA,MACN,UAAU,CAAC;AAAA,IACb;AAAA,EACF;AAAA,EAEA,wBAAwB;AA3C1B;AA4CI,UAAM,SAAS,IAAI,uBAAU,KAAK,IAAI;AACtC,UAAM,cACJ,KAAK,QAAQ,UAAQ,UAAK,OAAO,OAAO,YAAY,aAAa,gBAA5C,mBAAyD,SAAQ;AAExF,UAAM,gBAAgB,OAAO,QAAQ,KAAK,OAAO,OAAO,KAAK,EAC1D,IAAI,CAAC,CAAC,EAAE,KAAK,MAAM,KAAK,EACxB,OAAO,WAAS,KAAK,QAAQ,YAAY,CAAC,GAAG,OAAO,WAAW,EAAE,SAAS,KAAK,IAAI,CAAC;AAEvF,WAAO;AAAA,MACL,IAAI,oBAAO;AAAA,QACT,KAAK;AAAA,QACL,mBAAmB,CAAC,GAAG,IAAI,UAAU;AACnC,gBAAM,EAAE,KAAK,IAAI,OAAO,IAAI;AAC5B,gBAAM,wBAAwB,OAAO,SAAS,KAAK;AACnD,gBAAM,cAAc,IAAI,QAAQ;AAChC,gBAAM,OAAO,OAAO,MAAM,WAAW;AAErC,cAAI,CAAC,uBAAuB;AAC1B;AAAA,UACF;AAEA,iBAAO,GAAG,OAAO,aAAa,KAAK,OAAO,CAAC;AAAA,QAC7C;AAAA,QACA,OAAO;AAAA,UACL,MAAM,CAAC,GAAG,UAAU;AAClB,kBAAM,WAAW,MAAM,GAAG,IAAI;AAE9B,mBAAO,CAAC,eAAe,EAAE,MAAM,UAAU,OAAO,cAAc,CAAC;AAAA,UACjE;AAAA,UACA,OAAO,CAAC,IAAI,UAAU;AACpB,gBAAI,CAAC,GAAG,YAAY;AAClB,qBAAO;AAAA,YACT;AAIA,gBAAI,GAAG,QAAQ,uBAAuB,GAAG;AACvC,qBAAO;AAAA,YACT;AAEA,kBAAM,WAAW,GAAG,IAAI;AAExB,mBAAO,CAAC,eAAe,EAAE,MAAM,UAAU,OAAO,cAAc,CAAC;AAAA,UACjE;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AACF,CAAC;","names":[]}
@@ -0,0 +1,28 @@
import { Extension } from '@tiptap/core';
/**
* Extension based on:
* - https://github.com/ueberdosis/tiptap/blob/v1/packages/tiptap-extensions/src/extensions/TrailingNode.js
* - https://github.com/remirror/remirror/blob/e0f1bec4a1e8073ce8f5500d62193e52321155b9/packages/prosemirror-trailing-node/src/trailing-node-plugin.ts
*/
interface TrailingNodeOptions {
/**
* The node type that should be inserted at the end of the document.
* @note the node will always be added to the `notAfter` lists to
* prevent an infinite loop.
* @default undefined
*/
node?: string;
/**
* The node types after which the trailing node should not be inserted.
* @default ['paragraph']
*/
notAfter?: string | string[];
}
/**
* This extension allows you to add an extra node at the end of the document.
* @see https://www.tiptap.dev/api/extensions/trailing-node
*/
declare const TrailingNode: Extension<TrailingNodeOptions, any>;
export { TrailingNode, type TrailingNodeOptions };
+28
View File
@@ -0,0 +1,28 @@
import { Extension } from '@tiptap/core';
/**
* Extension based on:
* - https://github.com/ueberdosis/tiptap/blob/v1/packages/tiptap-extensions/src/extensions/TrailingNode.js
* - https://github.com/remirror/remirror/blob/e0f1bec4a1e8073ce8f5500d62193e52321155b9/packages/prosemirror-trailing-node/src/trailing-node-plugin.ts
*/
interface TrailingNodeOptions {
/**
* The node type that should be inserted at the end of the document.
* @note the node will always be added to the `notAfter` lists to
* prevent an infinite loop.
* @default undefined
*/
node?: string;
/**
* The node types after which the trailing node should not be inserted.
* @default ['paragraph']
*/
notAfter?: string | string[];
}
/**
* This extension allows you to add an extra node at the end of the document.
* @see https://www.tiptap.dev/api/extensions/trailing-node
*/
declare const TrailingNode: Extension<TrailingNodeOptions, any>;
export { TrailingNode, type TrailingNodeOptions };
+56
View File
@@ -0,0 +1,56 @@
// src/trailing-node/trailing-node.ts
import { Extension } from "@tiptap/core";
import { Plugin, PluginKey } from "@tiptap/pm/state";
function nodeEqualsType({ types, node }) {
return node && Array.isArray(types) && types.includes(node.type) || (node == null ? void 0 : node.type) === types;
}
var TrailingNode = Extension.create({
name: "trailingNode",
addOptions() {
return {
node: void 0,
notAfter: []
};
},
addProseMirrorPlugins() {
var _a;
const plugin = new PluginKey(this.name);
const defaultNode = this.options.node || ((_a = this.editor.schema.topNodeType.contentMatch.defaultType) == null ? void 0 : _a.name) || "paragraph";
const disabledNodes = Object.entries(this.editor.schema.nodes).map(([, value]) => value).filter((node) => (this.options.notAfter || []).concat(defaultNode).includes(node.name));
return [
new Plugin({
key: plugin,
appendTransaction: (_, __, state) => {
const { doc, tr, schema } = state;
const shouldInsertNodeAtEnd = plugin.getState(state);
const endPosition = doc.content.size;
const type = schema.nodes[defaultNode];
if (!shouldInsertNodeAtEnd) {
return;
}
return tr.insert(endPosition, type.create());
},
state: {
init: (_, state) => {
const lastNode = state.tr.doc.lastChild;
return !nodeEqualsType({ node: lastNode, types: disabledNodes });
},
apply: (tr, value) => {
if (!tr.docChanged) {
return value;
}
if (tr.getMeta("__uniqueIDTransaction")) {
return value;
}
const lastNode = tr.doc.lastChild;
return !nodeEqualsType({ node: lastNode, types: disabledNodes });
}
}
})
];
}
});
export {
TrailingNode
};
//# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
{"version":3,"sources":["../../src/trailing-node/trailing-node.ts"],"sourcesContent":["import { Extension } from '@tiptap/core'\nimport type { Node, NodeType } from '@tiptap/pm/model'\nimport { Plugin, PluginKey } from '@tiptap/pm/state'\n\nfunction nodeEqualsType({ types, node }: { types: NodeType | NodeType[]; node: Node | null | undefined }) {\n return (node && Array.isArray(types) && types.includes(node.type)) || node?.type === types\n}\n\n/**\n * Extension based on:\n * - https://github.com/ueberdosis/tiptap/blob/v1/packages/tiptap-extensions/src/extensions/TrailingNode.js\n * - https://github.com/remirror/remirror/blob/e0f1bec4a1e8073ce8f5500d62193e52321155b9/packages/prosemirror-trailing-node/src/trailing-node-plugin.ts\n */\n\nexport interface TrailingNodeOptions {\n /**\n * The node type that should be inserted at the end of the document.\n * @note the node will always be added to the `notAfter` lists to\n * prevent an infinite loop.\n * @default undefined\n */\n node?: string\n /**\n * The node types after which the trailing node should not be inserted.\n * @default ['paragraph']\n */\n notAfter?: string | string[]\n}\n\n/**\n * This extension allows you to add an extra node at the end of the document.\n * @see https://www.tiptap.dev/api/extensions/trailing-node\n */\nexport const TrailingNode = Extension.create<TrailingNodeOptions>({\n name: 'trailingNode',\n\n addOptions() {\n return {\n node: undefined,\n notAfter: [],\n }\n },\n\n addProseMirrorPlugins() {\n const plugin = new PluginKey(this.name)\n const defaultNode =\n this.options.node || this.editor.schema.topNodeType.contentMatch.defaultType?.name || 'paragraph'\n\n const disabledNodes = Object.entries(this.editor.schema.nodes)\n .map(([, value]) => value)\n .filter(node => (this.options.notAfter || []).concat(defaultNode).includes(node.name))\n\n return [\n new Plugin({\n key: plugin,\n appendTransaction: (_, __, state) => {\n const { doc, tr, schema } = state\n const shouldInsertNodeAtEnd = plugin.getState(state)\n const endPosition = doc.content.size\n const type = schema.nodes[defaultNode]\n\n if (!shouldInsertNodeAtEnd) {\n return\n }\n\n return tr.insert(endPosition, type.create())\n },\n state: {\n init: (_, state) => {\n const lastNode = state.tr.doc.lastChild\n\n return !nodeEqualsType({ node: lastNode, types: disabledNodes })\n },\n apply: (tr, value) => {\n if (!tr.docChanged) {\n return value\n }\n\n // Ignore transactions from UniqueID extension to prevent infinite loops\n // when UniqueID adds IDs to newly inserted trailing nodes\n if (tr.getMeta('__uniqueIDTransaction')) {\n return value\n }\n\n const lastNode = tr.doc.lastChild\n\n return !nodeEqualsType({ node: lastNode, types: disabledNodes })\n },\n },\n }),\n ]\n },\n})\n"],"mappings":";AAAA,SAAS,iBAAiB;AAE1B,SAAS,QAAQ,iBAAiB;AAElC,SAAS,eAAe,EAAE,OAAO,KAAK,GAAoE;AACxG,SAAQ,QAAQ,MAAM,QAAQ,KAAK,KAAK,MAAM,SAAS,KAAK,IAAI,MAAM,6BAAM,UAAS;AACvF;AA2BO,IAAM,eAAe,UAAU,OAA4B;AAAA,EAChE,MAAM;AAAA,EAEN,aAAa;AACX,WAAO;AAAA,MACL,MAAM;AAAA,MACN,UAAU,CAAC;AAAA,IACb;AAAA,EACF;AAAA,EAEA,wBAAwB;AA3C1B;AA4CI,UAAM,SAAS,IAAI,UAAU,KAAK,IAAI;AACtC,UAAM,cACJ,KAAK,QAAQ,UAAQ,UAAK,OAAO,OAAO,YAAY,aAAa,gBAA5C,mBAAyD,SAAQ;AAExF,UAAM,gBAAgB,OAAO,QAAQ,KAAK,OAAO,OAAO,KAAK,EAC1D,IAAI,CAAC,CAAC,EAAE,KAAK,MAAM,KAAK,EACxB,OAAO,WAAS,KAAK,QAAQ,YAAY,CAAC,GAAG,OAAO,WAAW,EAAE,SAAS,KAAK,IAAI,CAAC;AAEvF,WAAO;AAAA,MACL,IAAI,OAAO;AAAA,QACT,KAAK;AAAA,QACL,mBAAmB,CAAC,GAAG,IAAI,UAAU;AACnC,gBAAM,EAAE,KAAK,IAAI,OAAO,IAAI;AAC5B,gBAAM,wBAAwB,OAAO,SAAS,KAAK;AACnD,gBAAM,cAAc,IAAI,QAAQ;AAChC,gBAAM,OAAO,OAAO,MAAM,WAAW;AAErC,cAAI,CAAC,uBAAuB;AAC1B;AAAA,UACF;AAEA,iBAAO,GAAG,OAAO,aAAa,KAAK,OAAO,CAAC;AAAA,QAC7C;AAAA,QACA,OAAO;AAAA,UACL,MAAM,CAAC,GAAG,UAAU;AAClB,kBAAM,WAAW,MAAM,GAAG,IAAI;AAE9B,mBAAO,CAAC,eAAe,EAAE,MAAM,UAAU,OAAO,cAAc,CAAC;AAAA,UACjE;AAAA,UACA,OAAO,CAAC,IAAI,UAAU;AACpB,gBAAI,CAAC,GAAG,YAAY;AAClB,qBAAO;AAAA,YACT;AAIA,gBAAI,GAAG,QAAQ,uBAAuB,GAAG;AACvC,qBAAO;AAAA,YACT;AAEA,kBAAM,WAAW,GAAG,IAAI;AAExB,mBAAO,CAAC,eAAe,EAAE,MAAM,UAAU,OAAO,cAAc,CAAC;AAAA,UACjE;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AACF,CAAC;","names":[]}
+66
View File
@@ -0,0 +1,66 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/undo-redo/index.ts
var index_exports = {};
__export(index_exports, {
UndoRedo: () => UndoRedo
});
module.exports = __toCommonJS(index_exports);
// src/undo-redo/undo-redo.ts
var import_core = require("@tiptap/core");
var import_history = require("@tiptap/pm/history");
var UndoRedo = import_core.Extension.create({
name: "undoRedo",
addOptions() {
return {
depth: 100,
newGroupDelay: 500
};
},
addCommands() {
return {
undo: () => ({ state, dispatch }) => {
return (0, import_history.undo)(state, dispatch);
},
redo: () => ({ state, dispatch }) => {
return (0, import_history.redo)(state, dispatch);
}
};
},
addProseMirrorPlugins() {
return [(0, import_history.history)(this.options)];
},
addKeyboardShortcuts() {
return {
"Mod-z": () => this.editor.commands.undo(),
"Shift-Mod-z": () => this.editor.commands.redo(),
"Mod-y": () => this.editor.commands.redo(),
// Russian keyboard layouts
"Mod-\u044F": () => this.editor.commands.undo(),
"Shift-Mod-\u044F": () => this.editor.commands.redo()
};
}
});
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
UndoRedo
});
//# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
{"version":3,"sources":["../../src/undo-redo/index.ts","../../src/undo-redo/undo-redo.ts"],"sourcesContent":["export * from './undo-redo.js'\n","import { Extension } from '@tiptap/core'\nimport { history, redo, undo } from '@tiptap/pm/history'\n\nexport interface UndoRedoOptions {\n /**\n * The amount of history events that are collected before the oldest events are discarded.\n * @default 100\n * @example 50\n */\n depth: number\n\n /**\n * The delay (in milliseconds) between changes after which a new group should be started.\n * @default 500\n * @example 1000\n */\n newGroupDelay: number\n}\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n undoRedo: {\n /**\n * Undo recent changes\n * @example editor.commands.undo()\n */\n undo: () => ReturnType\n /**\n * Reapply reverted changes\n * @example editor.commands.redo()\n */\n redo: () => ReturnType\n }\n }\n}\n\n/**\n * This extension allows you to undo and redo recent changes.\n * @see https://www.tiptap.dev/api/extensions/undo-redo\n *\n * **Important**: If the `@tiptap/extension-collaboration` package is used, make sure to remove\n * the `undo-redo` extension, as it is not compatible with the `collaboration` extension.\n *\n * `@tiptap/extension-collaboration` uses its own history implementation.\n */\nexport const UndoRedo = Extension.create<UndoRedoOptions>({\n name: 'undoRedo',\n\n addOptions() {\n return {\n depth: 100,\n newGroupDelay: 500,\n }\n },\n\n addCommands() {\n return {\n undo:\n () =>\n ({ state, dispatch }) => {\n return undo(state, dispatch)\n },\n redo:\n () =>\n ({ state, dispatch }) => {\n return redo(state, dispatch)\n },\n }\n },\n\n addProseMirrorPlugins() {\n return [history(this.options)]\n },\n\n addKeyboardShortcuts() {\n return {\n 'Mod-z': () => this.editor.commands.undo(),\n 'Shift-Mod-z': () => this.editor.commands.redo(),\n 'Mod-y': () => this.editor.commands.redo(),\n\n // Russian keyboard layouts\n 'Mod-я': () => this.editor.commands.undo(),\n 'Shift-Mod-я': () => this.editor.commands.redo(),\n }\n },\n})\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,kBAA0B;AAC1B,qBAAoC;AA4C7B,IAAM,WAAW,sBAAU,OAAwB;AAAA,EACxD,MAAM;AAAA,EAEN,aAAa;AACX,WAAO;AAAA,MACL,OAAO;AAAA,MACP,eAAe;AAAA,IACjB;AAAA,EACF;AAAA,EAEA,cAAc;AACZ,WAAO;AAAA,MACL,MACE,MACA,CAAC,EAAE,OAAO,SAAS,MAAM;AACvB,mBAAO,qBAAK,OAAO,QAAQ;AAAA,MAC7B;AAAA,MACF,MACE,MACA,CAAC,EAAE,OAAO,SAAS,MAAM;AACvB,mBAAO,qBAAK,OAAO,QAAQ;AAAA,MAC7B;AAAA,IACJ;AAAA,EACF;AAAA,EAEA,wBAAwB;AACtB,WAAO,KAAC,wBAAQ,KAAK,OAAO,CAAC;AAAA,EAC/B;AAAA,EAEA,uBAAuB;AACrB,WAAO;AAAA,MACL,SAAS,MAAM,KAAK,OAAO,SAAS,KAAK;AAAA,MACzC,eAAe,MAAM,KAAK,OAAO,SAAS,KAAK;AAAA,MAC/C,SAAS,MAAM,KAAK,OAAO,SAAS,KAAK;AAAA;AAAA,MAGzC,cAAS,MAAM,KAAK,OAAO,SAAS,KAAK;AAAA,MACzC,oBAAe,MAAM,KAAK,OAAO,SAAS,KAAK;AAAA,IACjD;AAAA,EACF;AACF,CAAC;","names":[]}
+44
View File
@@ -0,0 +1,44 @@
import { Extension } from '@tiptap/core';
interface UndoRedoOptions {
/**
* The amount of history events that are collected before the oldest events are discarded.
* @default 100
* @example 50
*/
depth: number;
/**
* The delay (in milliseconds) between changes after which a new group should be started.
* @default 500
* @example 1000
*/
newGroupDelay: number;
}
declare module '@tiptap/core' {
interface Commands<ReturnType> {
undoRedo: {
/**
* Undo recent changes
* @example editor.commands.undo()
*/
undo: () => ReturnType;
/**
* Reapply reverted changes
* @example editor.commands.redo()
*/
redo: () => ReturnType;
};
}
}
/**
* This extension allows you to undo and redo recent changes.
* @see https://www.tiptap.dev/api/extensions/undo-redo
*
* **Important**: If the `@tiptap/extension-collaboration` package is used, make sure to remove
* the `undo-redo` extension, as it is not compatible with the `collaboration` extension.
*
* `@tiptap/extension-collaboration` uses its own history implementation.
*/
declare const UndoRedo: Extension<UndoRedoOptions, any>;
export { UndoRedo, type UndoRedoOptions };
+44
View File
@@ -0,0 +1,44 @@
import { Extension } from '@tiptap/core';
interface UndoRedoOptions {
/**
* The amount of history events that are collected before the oldest events are discarded.
* @default 100
* @example 50
*/
depth: number;
/**
* The delay (in milliseconds) between changes after which a new group should be started.
* @default 500
* @example 1000
*/
newGroupDelay: number;
}
declare module '@tiptap/core' {
interface Commands<ReturnType> {
undoRedo: {
/**
* Undo recent changes
* @example editor.commands.undo()
*/
undo: () => ReturnType;
/**
* Reapply reverted changes
* @example editor.commands.redo()
*/
redo: () => ReturnType;
};
}
}
/**
* This extension allows you to undo and redo recent changes.
* @see https://www.tiptap.dev/api/extensions/undo-redo
*
* **Important**: If the `@tiptap/extension-collaboration` package is used, make sure to remove
* the `undo-redo` extension, as it is not compatible with the `collaboration` extension.
*
* `@tiptap/extension-collaboration` uses its own history implementation.
*/
declare const UndoRedo: Extension<UndoRedoOptions, any>;
export { UndoRedo, type UndoRedoOptions };
+39
View File
@@ -0,0 +1,39 @@
// src/undo-redo/undo-redo.ts
import { Extension } from "@tiptap/core";
import { history, redo, undo } from "@tiptap/pm/history";
var UndoRedo = Extension.create({
name: "undoRedo",
addOptions() {
return {
depth: 100,
newGroupDelay: 500
};
},
addCommands() {
return {
undo: () => ({ state, dispatch }) => {
return undo(state, dispatch);
},
redo: () => ({ state, dispatch }) => {
return redo(state, dispatch);
}
};
},
addProseMirrorPlugins() {
return [history(this.options)];
},
addKeyboardShortcuts() {
return {
"Mod-z": () => this.editor.commands.undo(),
"Shift-Mod-z": () => this.editor.commands.redo(),
"Mod-y": () => this.editor.commands.redo(),
// Russian keyboard layouts
"Mod-\u044F": () => this.editor.commands.undo(),
"Shift-Mod-\u044F": () => this.editor.commands.redo()
};
}
});
export {
UndoRedo
};
//# sourceMappingURL=index.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../../src/undo-redo/undo-redo.ts"],"sourcesContent":["import { Extension } from '@tiptap/core'\nimport { history, redo, undo } from '@tiptap/pm/history'\n\nexport interface UndoRedoOptions {\n /**\n * The amount of history events that are collected before the oldest events are discarded.\n * @default 100\n * @example 50\n */\n depth: number\n\n /**\n * The delay (in milliseconds) between changes after which a new group should be started.\n * @default 500\n * @example 1000\n */\n newGroupDelay: number\n}\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n undoRedo: {\n /**\n * Undo recent changes\n * @example editor.commands.undo()\n */\n undo: () => ReturnType\n /**\n * Reapply reverted changes\n * @example editor.commands.redo()\n */\n redo: () => ReturnType\n }\n }\n}\n\n/**\n * This extension allows you to undo and redo recent changes.\n * @see https://www.tiptap.dev/api/extensions/undo-redo\n *\n * **Important**: If the `@tiptap/extension-collaboration` package is used, make sure to remove\n * the `undo-redo` extension, as it is not compatible with the `collaboration` extension.\n *\n * `@tiptap/extension-collaboration` uses its own history implementation.\n */\nexport const UndoRedo = Extension.create<UndoRedoOptions>({\n name: 'undoRedo',\n\n addOptions() {\n return {\n depth: 100,\n newGroupDelay: 500,\n }\n },\n\n addCommands() {\n return {\n undo:\n () =>\n ({ state, dispatch }) => {\n return undo(state, dispatch)\n },\n redo:\n () =>\n ({ state, dispatch }) => {\n return redo(state, dispatch)\n },\n }\n },\n\n addProseMirrorPlugins() {\n return [history(this.options)]\n },\n\n addKeyboardShortcuts() {\n return {\n 'Mod-z': () => this.editor.commands.undo(),\n 'Shift-Mod-z': () => this.editor.commands.redo(),\n 'Mod-y': () => this.editor.commands.redo(),\n\n // Russian keyboard layouts\n 'Mod-я': () => this.editor.commands.undo(),\n 'Shift-Mod-я': () => this.editor.commands.redo(),\n }\n },\n})\n"],"mappings":";AAAA,SAAS,iBAAiB;AAC1B,SAAS,SAAS,MAAM,YAAY;AA4C7B,IAAM,WAAW,UAAU,OAAwB;AAAA,EACxD,MAAM;AAAA,EAEN,aAAa;AACX,WAAO;AAAA,MACL,OAAO;AAAA,MACP,eAAe;AAAA,IACjB;AAAA,EACF;AAAA,EAEA,cAAc;AACZ,WAAO;AAAA,MACL,MACE,MACA,CAAC,EAAE,OAAO,SAAS,MAAM;AACvB,eAAO,KAAK,OAAO,QAAQ;AAAA,MAC7B;AAAA,MACF,MACE,MACA,CAAC,EAAE,OAAO,SAAS,MAAM;AACvB,eAAO,KAAK,OAAO,QAAQ;AAAA,MAC7B;AAAA,IACJ;AAAA,EACF;AAAA,EAEA,wBAAwB;AACtB,WAAO,CAAC,QAAQ,KAAK,OAAO,CAAC;AAAA,EAC/B;AAAA,EAEA,uBAAuB;AACrB,WAAO;AAAA,MACL,SAAS,MAAM,KAAK,OAAO,SAAS,KAAK;AAAA,MACzC,eAAe,MAAM,KAAK,OAAO,SAAS,KAAK;AAAA,MAC/C,SAAS,MAAM,KAAK,OAAO,SAAS,KAAK;AAAA;AAAA,MAGzC,cAAS,MAAM,KAAK,OAAO,SAAS,KAAK;AAAA,MACzC,oBAAe,MAAM,KAAK,OAAO,SAAS,KAAK;AAAA,IACjD;AAAA,EACF;AACF,CAAC;","names":[]}