@tiptap/extensions 3.0.0-next.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +21 -0
- package/README.md +18 -0
- package/dist/focus/index.cjs +95 -0
- package/dist/focus/index.cjs.map +1 -0
- package/dist/focus/index.d.cts +28 -0
- package/dist/focus/index.d.ts +28 -0
- package/dist/focus/index.js +68 -0
- package/dist/focus/index.js.map +1 -0
- package/dist/gap-cursor/index.cjs +51 -0
- package/dist/gap-cursor/index.cjs.map +1 -0
- package/dist/gap-cursor/index.d.cts +25 -0
- package/dist/gap-cursor/index.d.ts +25 -0
- package/dist/gap-cursor/index.js +24 -0
- package/dist/gap-cursor/index.js.map +1 -0
- package/dist/index.cjs +222 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +117 -0
- package/dist/index.d.ts +117 -0
- package/dist/index.js +191 -0
- package/dist/index.js.map +1 -0
- package/dist/selection/index.cjs +63 -0
- package/dist/selection/index.cjs.map +1 -0
- package/dist/selection/index.d.cts +17 -0
- package/dist/selection/index.d.ts +17 -0
- package/dist/selection/index.js +36 -0
- package/dist/selection/index.js.map +1 -0
- package/dist/trailing-node/index.cjs +78 -0
- package/dist/trailing-node/index.cjs.map +1 -0
- package/dist/trailing-node/index.d.cts +28 -0
- package/dist/trailing-node/index.d.ts +28 -0
- package/dist/trailing-node/index.js +51 -0
- package/dist/trailing-node/index.js.map +1 -0
- package/package.json +93 -0
- package/src/drop-cursor/drop-cursor.ts +47 -0
- package/src/drop-cursor/index.ts +1 -0
- package/src/focus/focus.ts +110 -0
- package/src/focus/index.ts +1 -0
- package/src/gap-cursor/gap-cursor.ts +46 -0
- package/src/gap-cursor/index.ts +1 -0
- package/src/index.ts +5 -0
- package/src/selection/index.ts +1 -0
- package/src/selection/selection.ts +51 -0
- package/src/trailing-node/index.ts +1 -0
- package/src/trailing-node/trailing-node.ts +84 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/trailing-node/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
TrailingNode: () => TrailingNode
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(index_exports);
|
|
26
|
+
|
|
27
|
+
// src/trailing-node/trailing-node.ts
|
|
28
|
+
var import_core = require("@tiptap/core");
|
|
29
|
+
var import_state = require("@tiptap/pm/state");
|
|
30
|
+
function nodeEqualsType({ types, node }) {
|
|
31
|
+
return node && Array.isArray(types) && types.includes(node.type) || (node == null ? void 0 : node.type) === types;
|
|
32
|
+
}
|
|
33
|
+
var TrailingNode = import_core.Extension.create({
|
|
34
|
+
name: "trailingNode",
|
|
35
|
+
addOptions() {
|
|
36
|
+
return {
|
|
37
|
+
node: "paragraph",
|
|
38
|
+
notAfter: []
|
|
39
|
+
};
|
|
40
|
+
},
|
|
41
|
+
addProseMirrorPlugins() {
|
|
42
|
+
const plugin = new import_state.PluginKey(this.name);
|
|
43
|
+
const disabledNodes = Object.entries(this.editor.schema.nodes).map(([, value]) => value).filter((node) => (this.options.notAfter || []).concat(this.options.node).includes(node.name));
|
|
44
|
+
return [
|
|
45
|
+
new import_state.Plugin({
|
|
46
|
+
key: plugin,
|
|
47
|
+
appendTransaction: (_, __, state) => {
|
|
48
|
+
const { doc, tr, schema } = state;
|
|
49
|
+
const shouldInsertNodeAtEnd = plugin.getState(state);
|
|
50
|
+
const endPosition = doc.content.size;
|
|
51
|
+
const type = schema.nodes[this.options.node];
|
|
52
|
+
if (!shouldInsertNodeAtEnd) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
return tr.insert(endPosition, type.create());
|
|
56
|
+
},
|
|
57
|
+
state: {
|
|
58
|
+
init: (_, state) => {
|
|
59
|
+
const lastNode = state.tr.doc.lastChild;
|
|
60
|
+
return !nodeEqualsType({ node: lastNode, types: disabledNodes });
|
|
61
|
+
},
|
|
62
|
+
apply: (tr, value) => {
|
|
63
|
+
if (!tr.docChanged) {
|
|
64
|
+
return value;
|
|
65
|
+
}
|
|
66
|
+
const lastNode = tr.doc.lastChild;
|
|
67
|
+
return !nodeEqualsType({ node: lastNode, types: disabledNodes });
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
})
|
|
71
|
+
];
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
75
|
+
0 && (module.exports = {
|
|
76
|
+
TrailingNode
|
|
77
|
+
});
|
|
78
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
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 { 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 'paragraph'\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: 'paragraph',\n notAfter: [],\n }\n },\n\n addProseMirrorPlugins() {\n const plugin = new PluginKey(this.name)\n const disabledNodes = Object.entries(this.editor.schema.nodes)\n .map(([, value]) => value)\n .filter(node => (this.options.notAfter || []).concat(this.options.node).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[this.options.node]\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 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;AACtB,UAAM,SAAS,IAAI,uBAAU,KAAK,IAAI;AACtC,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,KAAK,QAAQ,IAAI,EAAE,SAAS,KAAK,IAAI,CAAC;AAE7F,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,KAAK,QAAQ,IAAI;AAE3C,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;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 @@
|
|
|
1
|
+
import { Extension } from '@tiptap/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Extension based on:
|
|
5
|
+
* - https://github.com/ueberdosis/tiptap/blob/v1/packages/tiptap-extensions/src/extensions/TrailingNode.js
|
|
6
|
+
* - https://github.com/remirror/remirror/blob/e0f1bec4a1e8073ce8f5500d62193e52321155b9/packages/prosemirror-trailing-node/src/trailing-node-plugin.ts
|
|
7
|
+
*/
|
|
8
|
+
interface TrailingNodeOptions {
|
|
9
|
+
/**
|
|
10
|
+
* The node type that should be inserted at the end of the document.
|
|
11
|
+
* @note the node will always be added to the `notAfter` lists to
|
|
12
|
+
* prevent an infinite loop.
|
|
13
|
+
* @default 'paragraph'
|
|
14
|
+
*/
|
|
15
|
+
node: string;
|
|
16
|
+
/**
|
|
17
|
+
* The node types after which the trailing node should not be inserted.
|
|
18
|
+
* @default ['paragraph']
|
|
19
|
+
*/
|
|
20
|
+
notAfter?: string | string[];
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* This extension allows you to add an extra node at the end of the document.
|
|
24
|
+
* @see https://www.tiptap.dev/api/extensions/trailing-node
|
|
25
|
+
*/
|
|
26
|
+
declare const TrailingNode: Extension<TrailingNodeOptions, any>;
|
|
27
|
+
|
|
28
|
+
export { TrailingNode, type TrailingNodeOptions };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Extension } from '@tiptap/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Extension based on:
|
|
5
|
+
* - https://github.com/ueberdosis/tiptap/blob/v1/packages/tiptap-extensions/src/extensions/TrailingNode.js
|
|
6
|
+
* - https://github.com/remirror/remirror/blob/e0f1bec4a1e8073ce8f5500d62193e52321155b9/packages/prosemirror-trailing-node/src/trailing-node-plugin.ts
|
|
7
|
+
*/
|
|
8
|
+
interface TrailingNodeOptions {
|
|
9
|
+
/**
|
|
10
|
+
* The node type that should be inserted at the end of the document.
|
|
11
|
+
* @note the node will always be added to the `notAfter` lists to
|
|
12
|
+
* prevent an infinite loop.
|
|
13
|
+
* @default 'paragraph'
|
|
14
|
+
*/
|
|
15
|
+
node: string;
|
|
16
|
+
/**
|
|
17
|
+
* The node types after which the trailing node should not be inserted.
|
|
18
|
+
* @default ['paragraph']
|
|
19
|
+
*/
|
|
20
|
+
notAfter?: string | string[];
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* This extension allows you to add an extra node at the end of the document.
|
|
24
|
+
* @see https://www.tiptap.dev/api/extensions/trailing-node
|
|
25
|
+
*/
|
|
26
|
+
declare const TrailingNode: Extension<TrailingNodeOptions, any>;
|
|
27
|
+
|
|
28
|
+
export { TrailingNode, type TrailingNodeOptions };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// src/trailing-node/trailing-node.ts
|
|
2
|
+
import { Extension } from "@tiptap/core";
|
|
3
|
+
import { Plugin, PluginKey } from "@tiptap/pm/state";
|
|
4
|
+
function nodeEqualsType({ types, node }) {
|
|
5
|
+
return node && Array.isArray(types) && types.includes(node.type) || (node == null ? void 0 : node.type) === types;
|
|
6
|
+
}
|
|
7
|
+
var TrailingNode = Extension.create({
|
|
8
|
+
name: "trailingNode",
|
|
9
|
+
addOptions() {
|
|
10
|
+
return {
|
|
11
|
+
node: "paragraph",
|
|
12
|
+
notAfter: []
|
|
13
|
+
};
|
|
14
|
+
},
|
|
15
|
+
addProseMirrorPlugins() {
|
|
16
|
+
const plugin = new PluginKey(this.name);
|
|
17
|
+
const disabledNodes = Object.entries(this.editor.schema.nodes).map(([, value]) => value).filter((node) => (this.options.notAfter || []).concat(this.options.node).includes(node.name));
|
|
18
|
+
return [
|
|
19
|
+
new Plugin({
|
|
20
|
+
key: plugin,
|
|
21
|
+
appendTransaction: (_, __, state) => {
|
|
22
|
+
const { doc, tr, schema } = state;
|
|
23
|
+
const shouldInsertNodeAtEnd = plugin.getState(state);
|
|
24
|
+
const endPosition = doc.content.size;
|
|
25
|
+
const type = schema.nodes[this.options.node];
|
|
26
|
+
if (!shouldInsertNodeAtEnd) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
return tr.insert(endPosition, type.create());
|
|
30
|
+
},
|
|
31
|
+
state: {
|
|
32
|
+
init: (_, state) => {
|
|
33
|
+
const lastNode = state.tr.doc.lastChild;
|
|
34
|
+
return !nodeEqualsType({ node: lastNode, types: disabledNodes });
|
|
35
|
+
},
|
|
36
|
+
apply: (tr, value) => {
|
|
37
|
+
if (!tr.docChanged) {
|
|
38
|
+
return value;
|
|
39
|
+
}
|
|
40
|
+
const lastNode = tr.doc.lastChild;
|
|
41
|
+
return !nodeEqualsType({ node: lastNode, types: disabledNodes });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
})
|
|
45
|
+
];
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
export {
|
|
49
|
+
TrailingNode
|
|
50
|
+
};
|
|
51
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/trailing-node/trailing-node.ts"],"sourcesContent":["import { Extension } from '@tiptap/core'\nimport { 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 'paragraph'\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: 'paragraph',\n notAfter: [],\n }\n },\n\n addProseMirrorPlugins() {\n const plugin = new PluginKey(this.name)\n const disabledNodes = Object.entries(this.editor.schema.nodes)\n .map(([, value]) => value)\n .filter(node => (this.options.notAfter || []).concat(this.options.node).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[this.options.node]\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 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;AACtB,UAAM,SAAS,IAAI,UAAU,KAAK,IAAI;AACtC,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,KAAK,QAAQ,IAAI,EAAE,SAAS,KAAK,IAAI,CAAC;AAE7F,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,KAAK,QAAQ,IAAI;AAE3C,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;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":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tiptap/extensions",
|
|
3
|
+
"description": "various extensions for tiptap",
|
|
4
|
+
"version": "3.0.0-next.3",
|
|
5
|
+
"homepage": "https://tiptap.dev",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"tiptap",
|
|
8
|
+
"tiptap extension"
|
|
9
|
+
],
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"funding": {
|
|
12
|
+
"type": "github",
|
|
13
|
+
"url": "https://github.com/sponsors/ueberdosis"
|
|
14
|
+
},
|
|
15
|
+
"type": "module",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": {
|
|
19
|
+
"import": "./dist/index.d.ts",
|
|
20
|
+
"require": "./dist/index.d.cts"
|
|
21
|
+
},
|
|
22
|
+
"import": "./dist/index.js",
|
|
23
|
+
"require": "./dist/index.cjs"
|
|
24
|
+
},
|
|
25
|
+
"./drop-cursor": {
|
|
26
|
+
"types": {
|
|
27
|
+
"import": "./dist/drop-cursor/index.d.ts",
|
|
28
|
+
"require": "./dist/drop-cursor/index.d.cts"
|
|
29
|
+
},
|
|
30
|
+
"import": "./dist/drop-cursor/index.js",
|
|
31
|
+
"require": "./dist/drop-cursor/index.cjs"
|
|
32
|
+
},
|
|
33
|
+
"./focus": {
|
|
34
|
+
"types": {
|
|
35
|
+
"import": "./dist/focus/index.d.ts",
|
|
36
|
+
"require": "./dist/focus/index.d.cts"
|
|
37
|
+
},
|
|
38
|
+
"import": "./dist/focus/index.js",
|
|
39
|
+
"require": "./dist/focus/index.cjs"
|
|
40
|
+
},
|
|
41
|
+
"./gap-cursor": {
|
|
42
|
+
"types": {
|
|
43
|
+
"import": "./dist/gap-cursor/index.d.ts",
|
|
44
|
+
"require": "./dist/gap-cursor/index.d.cts"
|
|
45
|
+
},
|
|
46
|
+
"import": "./dist/gap-cursor/index.js",
|
|
47
|
+
"require": "./dist/gap-cursor/index.cjs"
|
|
48
|
+
},
|
|
49
|
+
"./selection": {
|
|
50
|
+
"types": {
|
|
51
|
+
"import": "./dist/selection/index.d.ts",
|
|
52
|
+
"require": "./dist/selection/index.d.cts"
|
|
53
|
+
},
|
|
54
|
+
"import": "./dist/selection/index.js",
|
|
55
|
+
"require": "./dist/selection/index.cjs"
|
|
56
|
+
},
|
|
57
|
+
"./trailing-node": {
|
|
58
|
+
"types": {
|
|
59
|
+
"import": "./dist/trailing-node/index.d.ts",
|
|
60
|
+
"require": "./dist/trailing-node/index.d.cts"
|
|
61
|
+
},
|
|
62
|
+
"import": "./dist/trailing-node/index.js",
|
|
63
|
+
"require": "./dist/trailing-node/index.cjs"
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"main": "dist/index.cjs",
|
|
67
|
+
"module": "dist/index.js",
|
|
68
|
+
"types": "dist/index.d.ts",
|
|
69
|
+
"files": [
|
|
70
|
+
"src",
|
|
71
|
+
"dist"
|
|
72
|
+
],
|
|
73
|
+
"devDependencies": {
|
|
74
|
+
"@tiptap/core": "^3.0.0-next.3",
|
|
75
|
+
"@tiptap/pm": "^3.0.0-next.3"
|
|
76
|
+
},
|
|
77
|
+
"peerDependencies": {
|
|
78
|
+
"@tiptap/core": "^3.0.0-next.3",
|
|
79
|
+
"@tiptap/pm": "^3.0.0-next.3"
|
|
80
|
+
},
|
|
81
|
+
"repository": {
|
|
82
|
+
"type": "git",
|
|
83
|
+
"url": "https://github.com/ueberdosis/tiptap",
|
|
84
|
+
"directory": "packages/extension"
|
|
85
|
+
},
|
|
86
|
+
"publishConfig": {
|
|
87
|
+
"access": "public"
|
|
88
|
+
},
|
|
89
|
+
"scripts": {
|
|
90
|
+
"build": "tsup",
|
|
91
|
+
"lint": "prettier ./src/ --check && eslint --cache --quiet --no-error-on-unmatched-pattern ./src/"
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Extension } from '@tiptap/core'
|
|
2
|
+
import { dropCursor } from '@tiptap/pm/dropcursor'
|
|
3
|
+
|
|
4
|
+
export interface DropcursorOptions {
|
|
5
|
+
/**
|
|
6
|
+
* The color of the drop cursor
|
|
7
|
+
* @default 'currentColor'
|
|
8
|
+
* @example 'red'
|
|
9
|
+
*/
|
|
10
|
+
color: string | undefined
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* The width of the drop cursor
|
|
14
|
+
* @default 1
|
|
15
|
+
* @example 2
|
|
16
|
+
*/
|
|
17
|
+
width: number | undefined
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The class of the drop cursor
|
|
21
|
+
* @default undefined
|
|
22
|
+
* @example 'drop-cursor'
|
|
23
|
+
*/
|
|
24
|
+
class: string | undefined
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* This extension allows you to add a drop cursor to your editor.
|
|
29
|
+
* A drop cursor is a line that appears when you drag and drop content
|
|
30
|
+
* in-between nodes.
|
|
31
|
+
* @see https://tiptap.dev/api/extensions/dropcursor
|
|
32
|
+
*/
|
|
33
|
+
export const Dropcursor = Extension.create<DropcursorOptions>({
|
|
34
|
+
name: 'dropCursor',
|
|
35
|
+
|
|
36
|
+
addOptions() {
|
|
37
|
+
return {
|
|
38
|
+
color: 'currentColor',
|
|
39
|
+
width: 1,
|
|
40
|
+
class: undefined,
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
addProseMirrorPlugins() {
|
|
45
|
+
return [dropCursor(this.options)]
|
|
46
|
+
},
|
|
47
|
+
})
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './drop-cursor.js'
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { Extension } from '@tiptap/core'
|
|
2
|
+
import { Plugin, PluginKey } from '@tiptap/pm/state'
|
|
3
|
+
import { Decoration, DecorationSet } from '@tiptap/pm/view'
|
|
4
|
+
|
|
5
|
+
export interface FocusOptions {
|
|
6
|
+
/**
|
|
7
|
+
* The class name that should be added to the focused node.
|
|
8
|
+
* @default 'has-focus'
|
|
9
|
+
* @example 'is-focused'
|
|
10
|
+
*/
|
|
11
|
+
className: string
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The mode by which the focused node is determined.
|
|
15
|
+
* - All: All nodes are marked as focused.
|
|
16
|
+
* - Deepest: Only the deepest node is marked as focused.
|
|
17
|
+
* - Shallowest: Only the shallowest node is marked as focused.
|
|
18
|
+
*
|
|
19
|
+
* @default 'all'
|
|
20
|
+
* @example 'deepest'
|
|
21
|
+
* @example 'shallowest'
|
|
22
|
+
*/
|
|
23
|
+
mode: 'all' | 'deepest' | 'shallowest'
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* This extension allows you to add a class to the focused node.
|
|
28
|
+
* @see https://www.tiptap.dev/api/extensions/focus
|
|
29
|
+
*/
|
|
30
|
+
export const Focus = Extension.create<FocusOptions>({
|
|
31
|
+
name: 'focus',
|
|
32
|
+
|
|
33
|
+
addOptions() {
|
|
34
|
+
return {
|
|
35
|
+
className: 'has-focus',
|
|
36
|
+
mode: 'all',
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
addProseMirrorPlugins() {
|
|
41
|
+
return [
|
|
42
|
+
new Plugin({
|
|
43
|
+
key: new PluginKey('focus'),
|
|
44
|
+
props: {
|
|
45
|
+
decorations: ({ doc, selection }) => {
|
|
46
|
+
const { isEditable, isFocused } = this.editor
|
|
47
|
+
const { anchor } = selection
|
|
48
|
+
const decorations: Decoration[] = []
|
|
49
|
+
|
|
50
|
+
if (!isEditable || !isFocused) {
|
|
51
|
+
return DecorationSet.create(doc, [])
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Maximum Levels
|
|
55
|
+
let maxLevels = 0
|
|
56
|
+
|
|
57
|
+
if (this.options.mode === 'deepest') {
|
|
58
|
+
doc.descendants((node, pos) => {
|
|
59
|
+
if (node.isText) {
|
|
60
|
+
return
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const isCurrent = anchor >= pos && anchor <= pos + node.nodeSize - 1
|
|
64
|
+
|
|
65
|
+
if (!isCurrent) {
|
|
66
|
+
return false
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
maxLevels += 1
|
|
70
|
+
})
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Loop through current
|
|
74
|
+
let currentLevel = 0
|
|
75
|
+
|
|
76
|
+
doc.descendants((node, pos) => {
|
|
77
|
+
if (node.isText) {
|
|
78
|
+
return false
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const isCurrent = anchor >= pos && anchor <= pos + node.nodeSize - 1
|
|
82
|
+
|
|
83
|
+
if (!isCurrent) {
|
|
84
|
+
return false
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
currentLevel += 1
|
|
88
|
+
|
|
89
|
+
const outOfScope =
|
|
90
|
+
(this.options.mode === 'deepest' && maxLevels - currentLevel > 0) ||
|
|
91
|
+
(this.options.mode === 'shallowest' && currentLevel > 1)
|
|
92
|
+
|
|
93
|
+
if (outOfScope) {
|
|
94
|
+
return this.options.mode === 'deepest'
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
decorations.push(
|
|
98
|
+
Decoration.node(pos, pos + node.nodeSize, {
|
|
99
|
+
class: this.options.className,
|
|
100
|
+
}),
|
|
101
|
+
)
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
return DecorationSet.create(doc, decorations)
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
}),
|
|
108
|
+
]
|
|
109
|
+
},
|
|
110
|
+
})
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './focus.js'
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { callOrReturn, Extension, getExtensionField, ParentConfig } from '@tiptap/core'
|
|
2
|
+
import { gapCursor } from '@tiptap/pm/gapcursor'
|
|
3
|
+
|
|
4
|
+
declare module '@tiptap/core' {
|
|
5
|
+
interface NodeConfig<Options, Storage> {
|
|
6
|
+
/**
|
|
7
|
+
* A function to determine whether the gap cursor is allowed at the current position. Must return `true` or `false`.
|
|
8
|
+
* @default null
|
|
9
|
+
*/
|
|
10
|
+
allowGapCursor?:
|
|
11
|
+
| boolean
|
|
12
|
+
| null
|
|
13
|
+
| ((this: {
|
|
14
|
+
name: string
|
|
15
|
+
options: Options
|
|
16
|
+
storage: Storage
|
|
17
|
+
parent: ParentConfig<NodeConfig<Options>>['allowGapCursor']
|
|
18
|
+
}) => boolean | null)
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* This extension allows you to add a gap cursor to your editor.
|
|
24
|
+
* A gap cursor is a cursor that appears when you click on a place
|
|
25
|
+
* where no content is present, for example inbetween nodes.
|
|
26
|
+
* @see https://tiptap.dev/api/extensions/gapcursor
|
|
27
|
+
*/
|
|
28
|
+
export const Gapcursor = Extension.create({
|
|
29
|
+
name: 'gapCursor',
|
|
30
|
+
|
|
31
|
+
addProseMirrorPlugins() {
|
|
32
|
+
return [gapCursor()]
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
extendNodeSchema(extension) {
|
|
36
|
+
const context = {
|
|
37
|
+
name: extension.name,
|
|
38
|
+
options: extension.options,
|
|
39
|
+
storage: extension.storage,
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
allowGapCursor: callOrReturn(getExtensionField(extension, 'allowGapCursor', context)) ?? null,
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
})
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './gap-cursor.js'
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './selection.js'
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Extension } from '@tiptap/core'
|
|
2
|
+
import { Plugin, PluginKey } from '@tiptap/pm/state'
|
|
3
|
+
import { Decoration, DecorationSet } from '@tiptap/pm/view'
|
|
4
|
+
|
|
5
|
+
export type SelectionOptions = {
|
|
6
|
+
/**
|
|
7
|
+
* The class name that should be added to the selected text.
|
|
8
|
+
* @default 'selection'
|
|
9
|
+
* @example 'is-selected'
|
|
10
|
+
*/
|
|
11
|
+
className: string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* This extension allows you to add a class to the selected text.
|
|
16
|
+
* @see https://www.tiptap.dev/api/extensions/selection
|
|
17
|
+
*/
|
|
18
|
+
export const Selection = Extension.create({
|
|
19
|
+
name: 'selection',
|
|
20
|
+
|
|
21
|
+
addOptions() {
|
|
22
|
+
return {
|
|
23
|
+
className: 'selection',
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
addProseMirrorPlugins() {
|
|
28
|
+
const { editor, options } = this
|
|
29
|
+
|
|
30
|
+
return [
|
|
31
|
+
new Plugin({
|
|
32
|
+
key: new PluginKey('selection'),
|
|
33
|
+
props: {
|
|
34
|
+
decorations(state) {
|
|
35
|
+
if (state.selection.empty || editor.isFocused) {
|
|
36
|
+
return null
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return DecorationSet.create(state.doc, [
|
|
40
|
+
Decoration.inline(state.selection.from, state.selection.to, {
|
|
41
|
+
class: options.className,
|
|
42
|
+
}),
|
|
43
|
+
])
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
}),
|
|
47
|
+
]
|
|
48
|
+
},
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
export default Selection
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './trailing-node.js'
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { Extension } from '@tiptap/core'
|
|
2
|
+
import { Node, NodeType } from '@tiptap/pm/model'
|
|
3
|
+
import { Plugin, PluginKey } from '@tiptap/pm/state'
|
|
4
|
+
|
|
5
|
+
function nodeEqualsType({ types, node }: { types: NodeType | NodeType[]; node: Node | null | undefined }) {
|
|
6
|
+
return (node && Array.isArray(types) && types.includes(node.type)) || node?.type === types
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Extension based on:
|
|
11
|
+
* - https://github.com/ueberdosis/tiptap/blob/v1/packages/tiptap-extensions/src/extensions/TrailingNode.js
|
|
12
|
+
* - https://github.com/remirror/remirror/blob/e0f1bec4a1e8073ce8f5500d62193e52321155b9/packages/prosemirror-trailing-node/src/trailing-node-plugin.ts
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
export interface TrailingNodeOptions {
|
|
16
|
+
/**
|
|
17
|
+
* The node type that should be inserted at the end of the document.
|
|
18
|
+
* @note the node will always be added to the `notAfter` lists to
|
|
19
|
+
* prevent an infinite loop.
|
|
20
|
+
* @default 'paragraph'
|
|
21
|
+
*/
|
|
22
|
+
node: string
|
|
23
|
+
/**
|
|
24
|
+
* The node types after which the trailing node should not be inserted.
|
|
25
|
+
* @default ['paragraph']
|
|
26
|
+
*/
|
|
27
|
+
notAfter?: string | string[]
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* This extension allows you to add an extra node at the end of the document.
|
|
32
|
+
* @see https://www.tiptap.dev/api/extensions/trailing-node
|
|
33
|
+
*/
|
|
34
|
+
export const TrailingNode = Extension.create<TrailingNodeOptions>({
|
|
35
|
+
name: 'trailingNode',
|
|
36
|
+
|
|
37
|
+
addOptions() {
|
|
38
|
+
return {
|
|
39
|
+
node: 'paragraph',
|
|
40
|
+
notAfter: [],
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
addProseMirrorPlugins() {
|
|
45
|
+
const plugin = new PluginKey(this.name)
|
|
46
|
+
const disabledNodes = Object.entries(this.editor.schema.nodes)
|
|
47
|
+
.map(([, value]) => value)
|
|
48
|
+
.filter(node => (this.options.notAfter || []).concat(this.options.node).includes(node.name))
|
|
49
|
+
|
|
50
|
+
return [
|
|
51
|
+
new Plugin({
|
|
52
|
+
key: plugin,
|
|
53
|
+
appendTransaction: (_, __, state) => {
|
|
54
|
+
const { doc, tr, schema } = state
|
|
55
|
+
const shouldInsertNodeAtEnd = plugin.getState(state)
|
|
56
|
+
const endPosition = doc.content.size
|
|
57
|
+
const type = schema.nodes[this.options.node]
|
|
58
|
+
|
|
59
|
+
if (!shouldInsertNodeAtEnd) {
|
|
60
|
+
return
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return tr.insert(endPosition, type.create())
|
|
64
|
+
},
|
|
65
|
+
state: {
|
|
66
|
+
init: (_, state) => {
|
|
67
|
+
const lastNode = state.tr.doc.lastChild
|
|
68
|
+
|
|
69
|
+
return !nodeEqualsType({ node: lastNode, types: disabledNodes })
|
|
70
|
+
},
|
|
71
|
+
apply: (tr, value) => {
|
|
72
|
+
if (!tr.docChanged) {
|
|
73
|
+
return value
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const lastNode = tr.doc.lastChild
|
|
77
|
+
|
|
78
|
+
return !nodeEqualsType({ node: lastNode, types: disabledNodes })
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
}),
|
|
82
|
+
]
|
|
83
|
+
},
|
|
84
|
+
})
|