@tiptap/extension-placeholder 2.5.0-beta.5 → 2.5.0-pre.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +2 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +3 -15
- package/dist/index.js.map +1 -1
- package/dist/index.umd.js +2 -14
- package/dist/index.umd.js.map +1 -1
- package/dist/packages/core/src/Extension.d.ts +8 -8
- package/dist/packages/core/src/types.d.ts +5 -0
- package/dist/packages/core/src/utilities/removeDuplicates.d.ts +2 -2
- package/dist/packages/extension-placeholder/src/placeholder.d.ts +0 -8
- package/package.json +5 -5
- package/src/placeholder.ts +3 -23
package/dist/index.cjs
CHANGED
|
@@ -19,7 +19,6 @@ const Placeholder = core.Extension.create({
|
|
|
19
19
|
emptyNodeClass: 'is-empty',
|
|
20
20
|
placeholder: 'Write something …',
|
|
21
21
|
showOnlyWhenEditable: true,
|
|
22
|
-
considerAnyAsEmpty: false,
|
|
23
22
|
showOnlyCurrent: true,
|
|
24
23
|
includeChildren: false,
|
|
25
24
|
};
|
|
@@ -30,27 +29,16 @@ const Placeholder = core.Extension.create({
|
|
|
30
29
|
key: new state.PluginKey('placeholder'),
|
|
31
30
|
props: {
|
|
32
31
|
decorations: ({ doc, selection }) => {
|
|
33
|
-
var _a;
|
|
34
32
|
const active = this.editor.isEditable || !this.options.showOnlyWhenEditable;
|
|
35
33
|
const { anchor } = selection;
|
|
36
34
|
const decorations = [];
|
|
37
35
|
if (!active) {
|
|
38
36
|
return null;
|
|
39
37
|
}
|
|
40
|
-
|
|
41
|
-
const { firstChild } = doc.content;
|
|
42
|
-
const isLeaf = firstChild && firstChild.type.isLeaf;
|
|
43
|
-
const isAtom = firstChild && firstChild.isAtom;
|
|
44
|
-
const isValidNode = this.options.considerAnyAsEmpty
|
|
45
|
-
? true
|
|
46
|
-
: firstChild && firstChild.type.name === ((_a = doc.type.contentMatch.defaultType) === null || _a === void 0 ? void 0 : _a.name);
|
|
47
|
-
const isEmptyDoc = doc.content.childCount <= 1
|
|
48
|
-
&& firstChild
|
|
49
|
-
&& isValidNode
|
|
50
|
-
&& (firstChild.nodeSize <= 2 && (!isLeaf || !isAtom));
|
|
38
|
+
const isEmptyDoc = this.editor.isEmpty;
|
|
51
39
|
doc.descendants((node, pos) => {
|
|
52
40
|
const hasAnchor = anchor >= pos && anchor <= pos + node.nodeSize;
|
|
53
|
-
const isEmpty = !node.isLeaf &&
|
|
41
|
+
const isEmpty = !node.isLeaf && core.isNodeEmpty(node);
|
|
54
42
|
if ((hasAnchor || !this.options.showOnlyCurrent) && isEmpty) {
|
|
55
43
|
const classes = [this.options.emptyNodeClass];
|
|
56
44
|
if (isEmptyDoc) {
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../src/placeholder.ts"],"sourcesContent":["import { Editor, Extension } from '@tiptap/core'\nimport { Node as ProsemirrorNode } from '@tiptap/pm/model'\nimport { Plugin, PluginKey } from '@tiptap/pm/state'\nimport { Decoration, DecorationSet } from '@tiptap/pm/view'\n\nexport interface PlaceholderOptions {\n /**\n * **The class name for the empty editor**\n * @default 'is-editor-empty'\n */\n emptyEditorClass: string\n\n /**\n * **The class name for empty nodes**\n * @default 'is-empty'\n */\n emptyNodeClass: string\n\n /**\n * **The placeholder content**\n *\n * You can use a function to return a dynamic placeholder or a string.\n * @default 'Write something …'\n */\n placeholder:\n | ((PlaceholderProps: {\n editor: Editor\n node: ProsemirrorNode\n pos: number\n hasAnchor: boolean\n }) => string)\n | string\n\n /**\n * **
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../src/placeholder.ts"],"sourcesContent":["import { Editor, Extension, isNodeEmpty } from '@tiptap/core'\nimport { Node as ProsemirrorNode } from '@tiptap/pm/model'\nimport { Plugin, PluginKey } from '@tiptap/pm/state'\nimport { Decoration, DecorationSet } from '@tiptap/pm/view'\n\nexport interface PlaceholderOptions {\n /**\n * **The class name for the empty editor**\n * @default 'is-editor-empty'\n */\n emptyEditorClass: string\n\n /**\n * **The class name for empty nodes**\n * @default 'is-empty'\n */\n emptyNodeClass: string\n\n /**\n * **The placeholder content**\n *\n * You can use a function to return a dynamic placeholder or a string.\n * @default 'Write something …'\n */\n placeholder:\n | ((PlaceholderProps: {\n editor: Editor\n node: ProsemirrorNode\n pos: number\n hasAnchor: boolean\n }) => string)\n | string\n\n /**\n * **Checks if the placeholder should be only shown when the editor is editable.**\n *\n * If true, the placeholder will only be shown when the editor is editable.\n * If false, the placeholder will always be shown.\n * @default true\n */\n showOnlyWhenEditable: boolean\n\n /**\n * **Checks if the placeholder should be only shown when the current node is empty.**\n *\n * If true, the placeholder will only be shown when the current node is empty.\n * If false, the placeholder will be shown when any node is empty.\n * @default true\n */\n showOnlyCurrent: boolean\n\n /**\n * **Controls if the placeholder should be shown for all descendents.**\n *\n * If true, the placeholder will be shown for all descendents.\n * If false, the placeholder will only be shown for the current node.\n * @default false\n */\n includeChildren: boolean\n}\n\n/**\n * This extension allows you to add a placeholder to your editor.\n * A placeholder is a text that appears when the editor or a node is empty.\n * @see https://www.tiptap.dev/api/extensions/placeholder\n */\nexport const Placeholder = Extension.create<PlaceholderOptions>({\n name: 'placeholder',\n\n addOptions() {\n return {\n emptyEditorClass: 'is-editor-empty',\n emptyNodeClass: 'is-empty',\n placeholder: 'Write something …',\n showOnlyWhenEditable: true,\n showOnlyCurrent: true,\n includeChildren: false,\n }\n },\n\n addProseMirrorPlugins() {\n return [\n new Plugin({\n key: new PluginKey('placeholder'),\n props: {\n decorations: ({ doc, selection }) => {\n const active = this.editor.isEditable || !this.options.showOnlyWhenEditable\n const { anchor } = selection\n const decorations: Decoration[] = []\n\n if (!active) {\n return null\n }\n\n const isEmptyDoc = this.editor.isEmpty\n\n doc.descendants((node, pos) => {\n const hasAnchor = anchor >= pos && anchor <= pos + node.nodeSize\n const isEmpty = !node.isLeaf && isNodeEmpty(node)\n\n if ((hasAnchor || !this.options.showOnlyCurrent) && isEmpty) {\n const classes = [this.options.emptyNodeClass]\n\n if (isEmptyDoc) {\n classes.push(this.options.emptyEditorClass)\n }\n\n const decoration = Decoration.node(pos, pos + node.nodeSize, {\n class: classes.join(' '),\n 'data-placeholder':\n typeof this.options.placeholder === 'function'\n ? this.options.placeholder({\n editor: this.editor,\n node,\n pos,\n hasAnchor,\n })\n : this.options.placeholder,\n })\n\n decorations.push(decoration)\n }\n\n return this.options.includeChildren\n })\n\n return DecorationSet.create(doc, decorations)\n },\n },\n }),\n ]\n },\n})\n"],"names":["Extension","Plugin","PluginKey","isNodeEmpty","Decoration","DecorationSet"],"mappings":";;;;;;;;AA6DA;;;;AAIG;AACU,MAAA,WAAW,GAAGA,cAAS,CAAC,MAAM,CAAqB;AAC9D,IAAA,IAAI,EAAE,aAAa;IAEnB,UAAU,GAAA;QACR,OAAO;AACL,YAAA,gBAAgB,EAAE,iBAAiB;AACnC,YAAA,cAAc,EAAE,UAAU;AAC1B,YAAA,WAAW,EAAE,mBAAmB;AAChC,YAAA,oBAAoB,EAAE,IAAI;AAC1B,YAAA,eAAe,EAAE,IAAI;AACrB,YAAA,eAAe,EAAE,KAAK;SACvB,CAAA;KACF;IAED,qBAAqB,GAAA;QACnB,OAAO;AACL,YAAA,IAAIC,YAAM,CAAC;AACT,gBAAA,GAAG,EAAE,IAAIC,eAAS,CAAC,aAAa,CAAC;AACjC,gBAAA,KAAK,EAAE;oBACL,WAAW,EAAE,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,KAAI;AAClC,wBAAA,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,oBAAoB,CAAA;AAC3E,wBAAA,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAA;wBAC5B,MAAM,WAAW,GAAiB,EAAE,CAAA;wBAEpC,IAAI,CAAC,MAAM,EAAE;AACX,4BAAA,OAAO,IAAI,CAAA;yBACZ;AAED,wBAAA,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAA;wBAEtC,GAAG,CAAC,WAAW,CAAC,CAAC,IAAI,EAAE,GAAG,KAAI;AAC5B,4BAAA,MAAM,SAAS,GAAG,MAAM,IAAI,GAAG,IAAI,MAAM,IAAI,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAA;4BAChE,MAAM,OAAO,GAAG,CAAC,IAAI,CAAC,MAAM,IAAIC,gBAAW,CAAC,IAAI,CAAC,CAAA;AAEjD,4BAAA,IAAI,CAAC,SAAS,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,eAAe,KAAK,OAAO,EAAE;gCAC3D,MAAM,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,CAAA;gCAE7C,IAAI,UAAU,EAAE;oCACd,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAA;iCAC5C;AAED,gCAAA,MAAM,UAAU,GAAGC,eAAU,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI,CAAC,QAAQ,EAAE;AAC3D,oCAAA,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC;oCACxB,kBAAkB,EAChB,OAAO,IAAI,CAAC,OAAO,CAAC,WAAW,KAAK,UAAU;AAC5C,0CAAE,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC;4CACzB,MAAM,EAAE,IAAI,CAAC,MAAM;4CACnB,IAAI;4CACJ,GAAG;4CACH,SAAS;yCACV,CAAC;AACF,0CAAE,IAAI,CAAC,OAAO,CAAC,WAAW;AAC/B,iCAAA,CAAC,CAAA;AAEF,gCAAA,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;6BAC7B;AAED,4BAAA,OAAO,IAAI,CAAC,OAAO,CAAC,eAAe,CAAA;AACrC,yBAAC,CAAC,CAAA;wBAEF,OAAOC,kBAAa,CAAC,MAAM,CAAC,GAAG,EAAE,WAAW,CAAC,CAAA;qBAC9C;AACF,iBAAA;aACF,CAAC;SACH,CAAA;KACF;AACF,CAAA;;;;;"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Extension } from '@tiptap/core';
|
|
1
|
+
import { Extension, isNodeEmpty } from '@tiptap/core';
|
|
2
2
|
import { Plugin, PluginKey } from '@tiptap/pm/state';
|
|
3
3
|
import { Decoration, DecorationSet } from '@tiptap/pm/view';
|
|
4
4
|
|
|
@@ -15,7 +15,6 @@ const Placeholder = Extension.create({
|
|
|
15
15
|
emptyNodeClass: 'is-empty',
|
|
16
16
|
placeholder: 'Write something …',
|
|
17
17
|
showOnlyWhenEditable: true,
|
|
18
|
-
considerAnyAsEmpty: false,
|
|
19
18
|
showOnlyCurrent: true,
|
|
20
19
|
includeChildren: false,
|
|
21
20
|
};
|
|
@@ -26,27 +25,16 @@ const Placeholder = Extension.create({
|
|
|
26
25
|
key: new PluginKey('placeholder'),
|
|
27
26
|
props: {
|
|
28
27
|
decorations: ({ doc, selection }) => {
|
|
29
|
-
var _a;
|
|
30
28
|
const active = this.editor.isEditable || !this.options.showOnlyWhenEditable;
|
|
31
29
|
const { anchor } = selection;
|
|
32
30
|
const decorations = [];
|
|
33
31
|
if (!active) {
|
|
34
32
|
return null;
|
|
35
33
|
}
|
|
36
|
-
|
|
37
|
-
const { firstChild } = doc.content;
|
|
38
|
-
const isLeaf = firstChild && firstChild.type.isLeaf;
|
|
39
|
-
const isAtom = firstChild && firstChild.isAtom;
|
|
40
|
-
const isValidNode = this.options.considerAnyAsEmpty
|
|
41
|
-
? true
|
|
42
|
-
: firstChild && firstChild.type.name === ((_a = doc.type.contentMatch.defaultType) === null || _a === void 0 ? void 0 : _a.name);
|
|
43
|
-
const isEmptyDoc = doc.content.childCount <= 1
|
|
44
|
-
&& firstChild
|
|
45
|
-
&& isValidNode
|
|
46
|
-
&& (firstChild.nodeSize <= 2 && (!isLeaf || !isAtom));
|
|
34
|
+
const isEmptyDoc = this.editor.isEmpty;
|
|
47
35
|
doc.descendants((node, pos) => {
|
|
48
36
|
const hasAnchor = anchor >= pos && anchor <= pos + node.nodeSize;
|
|
49
|
-
const isEmpty = !node.isLeaf &&
|
|
37
|
+
const isEmpty = !node.isLeaf && isNodeEmpty(node);
|
|
50
38
|
if ((hasAnchor || !this.options.showOnlyCurrent) && isEmpty) {
|
|
51
39
|
const classes = [this.options.emptyNodeClass];
|
|
52
40
|
if (isEmptyDoc) {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/placeholder.ts"],"sourcesContent":["import { Editor, Extension } from '@tiptap/core'\nimport { Node as ProsemirrorNode } from '@tiptap/pm/model'\nimport { Plugin, PluginKey } from '@tiptap/pm/state'\nimport { Decoration, DecorationSet } from '@tiptap/pm/view'\n\nexport interface PlaceholderOptions {\n /**\n * **The class name for the empty editor**\n * @default 'is-editor-empty'\n */\n emptyEditorClass: string\n\n /**\n * **The class name for empty nodes**\n * @default 'is-empty'\n */\n emptyNodeClass: string\n\n /**\n * **The placeholder content**\n *\n * You can use a function to return a dynamic placeholder or a string.\n * @default 'Write something …'\n */\n placeholder:\n | ((PlaceholderProps: {\n editor: Editor\n node: ProsemirrorNode\n pos: number\n hasAnchor: boolean\n }) => string)\n | string\n\n /**\n * **
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/placeholder.ts"],"sourcesContent":["import { Editor, Extension, isNodeEmpty } from '@tiptap/core'\nimport { Node as ProsemirrorNode } from '@tiptap/pm/model'\nimport { Plugin, PluginKey } from '@tiptap/pm/state'\nimport { Decoration, DecorationSet } from '@tiptap/pm/view'\n\nexport interface PlaceholderOptions {\n /**\n * **The class name for the empty editor**\n * @default 'is-editor-empty'\n */\n emptyEditorClass: string\n\n /**\n * **The class name for empty nodes**\n * @default 'is-empty'\n */\n emptyNodeClass: string\n\n /**\n * **The placeholder content**\n *\n * You can use a function to return a dynamic placeholder or a string.\n * @default 'Write something …'\n */\n placeholder:\n | ((PlaceholderProps: {\n editor: Editor\n node: ProsemirrorNode\n pos: number\n hasAnchor: boolean\n }) => string)\n | string\n\n /**\n * **Checks if the placeholder should be only shown when the editor is editable.**\n *\n * If true, the placeholder will only be shown when the editor is editable.\n * If false, the placeholder will always be shown.\n * @default true\n */\n showOnlyWhenEditable: boolean\n\n /**\n * **Checks if the placeholder should be only shown when the current node is empty.**\n *\n * If true, the placeholder will only be shown when the current node is empty.\n * If false, the placeholder will be shown when any node is empty.\n * @default true\n */\n showOnlyCurrent: boolean\n\n /**\n * **Controls if the placeholder should be shown for all descendents.**\n *\n * If true, the placeholder will be shown for all descendents.\n * If false, the placeholder will only be shown for the current node.\n * @default false\n */\n includeChildren: boolean\n}\n\n/**\n * This extension allows you to add a placeholder to your editor.\n * A placeholder is a text that appears when the editor or a node is empty.\n * @see https://www.tiptap.dev/api/extensions/placeholder\n */\nexport const Placeholder = Extension.create<PlaceholderOptions>({\n name: 'placeholder',\n\n addOptions() {\n return {\n emptyEditorClass: 'is-editor-empty',\n emptyNodeClass: 'is-empty',\n placeholder: 'Write something …',\n showOnlyWhenEditable: true,\n showOnlyCurrent: true,\n includeChildren: false,\n }\n },\n\n addProseMirrorPlugins() {\n return [\n new Plugin({\n key: new PluginKey('placeholder'),\n props: {\n decorations: ({ doc, selection }) => {\n const active = this.editor.isEditable || !this.options.showOnlyWhenEditable\n const { anchor } = selection\n const decorations: Decoration[] = []\n\n if (!active) {\n return null\n }\n\n const isEmptyDoc = this.editor.isEmpty\n\n doc.descendants((node, pos) => {\n const hasAnchor = anchor >= pos && anchor <= pos + node.nodeSize\n const isEmpty = !node.isLeaf && isNodeEmpty(node)\n\n if ((hasAnchor || !this.options.showOnlyCurrent) && isEmpty) {\n const classes = [this.options.emptyNodeClass]\n\n if (isEmptyDoc) {\n classes.push(this.options.emptyEditorClass)\n }\n\n const decoration = Decoration.node(pos, pos + node.nodeSize, {\n class: classes.join(' '),\n 'data-placeholder':\n typeof this.options.placeholder === 'function'\n ? this.options.placeholder({\n editor: this.editor,\n node,\n pos,\n hasAnchor,\n })\n : this.options.placeholder,\n })\n\n decorations.push(decoration)\n }\n\n return this.options.includeChildren\n })\n\n return DecorationSet.create(doc, decorations)\n },\n },\n }),\n ]\n },\n})\n"],"names":[],"mappings":";;;;AA6DA;;;;AAIG;AACU,MAAA,WAAW,GAAG,SAAS,CAAC,MAAM,CAAqB;AAC9D,IAAA,IAAI,EAAE,aAAa;IAEnB,UAAU,GAAA;QACR,OAAO;AACL,YAAA,gBAAgB,EAAE,iBAAiB;AACnC,YAAA,cAAc,EAAE,UAAU;AAC1B,YAAA,WAAW,EAAE,mBAAmB;AAChC,YAAA,oBAAoB,EAAE,IAAI;AAC1B,YAAA,eAAe,EAAE,IAAI;AACrB,YAAA,eAAe,EAAE,KAAK;SACvB,CAAA;KACF;IAED,qBAAqB,GAAA;QACnB,OAAO;AACL,YAAA,IAAI,MAAM,CAAC;AACT,gBAAA,GAAG,EAAE,IAAI,SAAS,CAAC,aAAa,CAAC;AACjC,gBAAA,KAAK,EAAE;oBACL,WAAW,EAAE,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,KAAI;AAClC,wBAAA,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,oBAAoB,CAAA;AAC3E,wBAAA,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAA;wBAC5B,MAAM,WAAW,GAAiB,EAAE,CAAA;wBAEpC,IAAI,CAAC,MAAM,EAAE;AACX,4BAAA,OAAO,IAAI,CAAA;yBACZ;AAED,wBAAA,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAA;wBAEtC,GAAG,CAAC,WAAW,CAAC,CAAC,IAAI,EAAE,GAAG,KAAI;AAC5B,4BAAA,MAAM,SAAS,GAAG,MAAM,IAAI,GAAG,IAAI,MAAM,IAAI,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAA;4BAChE,MAAM,OAAO,GAAG,CAAC,IAAI,CAAC,MAAM,IAAI,WAAW,CAAC,IAAI,CAAC,CAAA;AAEjD,4BAAA,IAAI,CAAC,SAAS,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,eAAe,KAAK,OAAO,EAAE;gCAC3D,MAAM,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,CAAA;gCAE7C,IAAI,UAAU,EAAE;oCACd,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAA;iCAC5C;AAED,gCAAA,MAAM,UAAU,GAAG,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI,CAAC,QAAQ,EAAE;AAC3D,oCAAA,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC;oCACxB,kBAAkB,EAChB,OAAO,IAAI,CAAC,OAAO,CAAC,WAAW,KAAK,UAAU;AAC5C,0CAAE,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC;4CACzB,MAAM,EAAE,IAAI,CAAC,MAAM;4CACnB,IAAI;4CACJ,GAAG;4CACH,SAAS;yCACV,CAAC;AACF,0CAAE,IAAI,CAAC,OAAO,CAAC,WAAW;AAC/B,iCAAA,CAAC,CAAA;AAEF,gCAAA,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;6BAC7B;AAED,4BAAA,OAAO,IAAI,CAAC,OAAO,CAAC,eAAe,CAAA;AACrC,yBAAC,CAAC,CAAA;wBAEF,OAAO,aAAa,CAAC,MAAM,CAAC,GAAG,EAAE,WAAW,CAAC,CAAA;qBAC9C;AACF,iBAAA;aACF,CAAC;SACH,CAAA;KACF;AACF,CAAA;;;;"}
|
package/dist/index.umd.js
CHANGED
|
@@ -17,7 +17,6 @@
|
|
|
17
17
|
emptyNodeClass: 'is-empty',
|
|
18
18
|
placeholder: 'Write something …',
|
|
19
19
|
showOnlyWhenEditable: true,
|
|
20
|
-
considerAnyAsEmpty: false,
|
|
21
20
|
showOnlyCurrent: true,
|
|
22
21
|
includeChildren: false,
|
|
23
22
|
};
|
|
@@ -28,27 +27,16 @@
|
|
|
28
27
|
key: new state.PluginKey('placeholder'),
|
|
29
28
|
props: {
|
|
30
29
|
decorations: ({ doc, selection }) => {
|
|
31
|
-
var _a;
|
|
32
30
|
const active = this.editor.isEditable || !this.options.showOnlyWhenEditable;
|
|
33
31
|
const { anchor } = selection;
|
|
34
32
|
const decorations = [];
|
|
35
33
|
if (!active) {
|
|
36
34
|
return null;
|
|
37
35
|
}
|
|
38
|
-
|
|
39
|
-
const { firstChild } = doc.content;
|
|
40
|
-
const isLeaf = firstChild && firstChild.type.isLeaf;
|
|
41
|
-
const isAtom = firstChild && firstChild.isAtom;
|
|
42
|
-
const isValidNode = this.options.considerAnyAsEmpty
|
|
43
|
-
? true
|
|
44
|
-
: firstChild && firstChild.type.name === ((_a = doc.type.contentMatch.defaultType) === null || _a === void 0 ? void 0 : _a.name);
|
|
45
|
-
const isEmptyDoc = doc.content.childCount <= 1
|
|
46
|
-
&& firstChild
|
|
47
|
-
&& isValidNode
|
|
48
|
-
&& (firstChild.nodeSize <= 2 && (!isLeaf || !isAtom));
|
|
36
|
+
const isEmptyDoc = this.editor.isEmpty;
|
|
49
37
|
doc.descendants((node, pos) => {
|
|
50
38
|
const hasAnchor = anchor >= pos && anchor <= pos + node.nodeSize;
|
|
51
|
-
const isEmpty = !node.isLeaf &&
|
|
39
|
+
const isEmpty = !node.isLeaf && core.isNodeEmpty(node);
|
|
52
40
|
if ((hasAnchor || !this.options.showOnlyCurrent) && isEmpty) {
|
|
53
41
|
const classes = [this.options.emptyNodeClass];
|
|
54
42
|
if (isEmptyDoc) {
|
package/dist/index.umd.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.umd.js","sources":["../src/placeholder.ts"],"sourcesContent":["import { Editor, Extension } from '@tiptap/core'\nimport { Node as ProsemirrorNode } from '@tiptap/pm/model'\nimport { Plugin, PluginKey } from '@tiptap/pm/state'\nimport { Decoration, DecorationSet } from '@tiptap/pm/view'\n\nexport interface PlaceholderOptions {\n /**\n * **The class name for the empty editor**\n * @default 'is-editor-empty'\n */\n emptyEditorClass: string\n\n /**\n * **The class name for empty nodes**\n * @default 'is-empty'\n */\n emptyNodeClass: string\n\n /**\n * **The placeholder content**\n *\n * You can use a function to return a dynamic placeholder or a string.\n * @default 'Write something …'\n */\n placeholder:\n | ((PlaceholderProps: {\n editor: Editor\n node: ProsemirrorNode\n pos: number\n hasAnchor: boolean\n }) => string)\n | string\n\n /**\n * **
|
|
1
|
+
{"version":3,"file":"index.umd.js","sources":["../src/placeholder.ts"],"sourcesContent":["import { Editor, Extension, isNodeEmpty } from '@tiptap/core'\nimport { Node as ProsemirrorNode } from '@tiptap/pm/model'\nimport { Plugin, PluginKey } from '@tiptap/pm/state'\nimport { Decoration, DecorationSet } from '@tiptap/pm/view'\n\nexport interface PlaceholderOptions {\n /**\n * **The class name for the empty editor**\n * @default 'is-editor-empty'\n */\n emptyEditorClass: string\n\n /**\n * **The class name for empty nodes**\n * @default 'is-empty'\n */\n emptyNodeClass: string\n\n /**\n * **The placeholder content**\n *\n * You can use a function to return a dynamic placeholder or a string.\n * @default 'Write something …'\n */\n placeholder:\n | ((PlaceholderProps: {\n editor: Editor\n node: ProsemirrorNode\n pos: number\n hasAnchor: boolean\n }) => string)\n | string\n\n /**\n * **Checks if the placeholder should be only shown when the editor is editable.**\n *\n * If true, the placeholder will only be shown when the editor is editable.\n * If false, the placeholder will always be shown.\n * @default true\n */\n showOnlyWhenEditable: boolean\n\n /**\n * **Checks if the placeholder should be only shown when the current node is empty.**\n *\n * If true, the placeholder will only be shown when the current node is empty.\n * If false, the placeholder will be shown when any node is empty.\n * @default true\n */\n showOnlyCurrent: boolean\n\n /**\n * **Controls if the placeholder should be shown for all descendents.**\n *\n * If true, the placeholder will be shown for all descendents.\n * If false, the placeholder will only be shown for the current node.\n * @default false\n */\n includeChildren: boolean\n}\n\n/**\n * This extension allows you to add a placeholder to your editor.\n * A placeholder is a text that appears when the editor or a node is empty.\n * @see https://www.tiptap.dev/api/extensions/placeholder\n */\nexport const Placeholder = Extension.create<PlaceholderOptions>({\n name: 'placeholder',\n\n addOptions() {\n return {\n emptyEditorClass: 'is-editor-empty',\n emptyNodeClass: 'is-empty',\n placeholder: 'Write something …',\n showOnlyWhenEditable: true,\n showOnlyCurrent: true,\n includeChildren: false,\n }\n },\n\n addProseMirrorPlugins() {\n return [\n new Plugin({\n key: new PluginKey('placeholder'),\n props: {\n decorations: ({ doc, selection }) => {\n const active = this.editor.isEditable || !this.options.showOnlyWhenEditable\n const { anchor } = selection\n const decorations: Decoration[] = []\n\n if (!active) {\n return null\n }\n\n const isEmptyDoc = this.editor.isEmpty\n\n doc.descendants((node, pos) => {\n const hasAnchor = anchor >= pos && anchor <= pos + node.nodeSize\n const isEmpty = !node.isLeaf && isNodeEmpty(node)\n\n if ((hasAnchor || !this.options.showOnlyCurrent) && isEmpty) {\n const classes = [this.options.emptyNodeClass]\n\n if (isEmptyDoc) {\n classes.push(this.options.emptyEditorClass)\n }\n\n const decoration = Decoration.node(pos, pos + node.nodeSize, {\n class: classes.join(' '),\n 'data-placeholder':\n typeof this.options.placeholder === 'function'\n ? this.options.placeholder({\n editor: this.editor,\n node,\n pos,\n hasAnchor,\n })\n : this.options.placeholder,\n })\n\n decorations.push(decoration)\n }\n\n return this.options.includeChildren\n })\n\n return DecorationSet.create(doc, decorations)\n },\n },\n }),\n ]\n },\n})\n"],"names":["Extension","Plugin","PluginKey","isNodeEmpty","Decoration","DecorationSet"],"mappings":";;;;;;EA6DA;;;;EAIG;AACU,QAAA,WAAW,GAAGA,cAAS,CAAC,MAAM,CAAqB;EAC9D,IAAA,IAAI,EAAE,aAAa;MAEnB,UAAU,GAAA;UACR,OAAO;EACL,YAAA,gBAAgB,EAAE,iBAAiB;EACnC,YAAA,cAAc,EAAE,UAAU;EAC1B,YAAA,WAAW,EAAE,mBAAmB;EAChC,YAAA,oBAAoB,EAAE,IAAI;EAC1B,YAAA,eAAe,EAAE,IAAI;EACrB,YAAA,eAAe,EAAE,KAAK;WACvB,CAAA;OACF;MAED,qBAAqB,GAAA;UACnB,OAAO;EACL,YAAA,IAAIC,YAAM,CAAC;EACT,gBAAA,GAAG,EAAE,IAAIC,eAAS,CAAC,aAAa,CAAC;EACjC,gBAAA,KAAK,EAAE;sBACL,WAAW,EAAE,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,KAAI;EAClC,wBAAA,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,oBAAoB,CAAA;EAC3E,wBAAA,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAA;0BAC5B,MAAM,WAAW,GAAiB,EAAE,CAAA;0BAEpC,IAAI,CAAC,MAAM,EAAE;EACX,4BAAA,OAAO,IAAI,CAAA;2BACZ;EAED,wBAAA,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAA;0BAEtC,GAAG,CAAC,WAAW,CAAC,CAAC,IAAI,EAAE,GAAG,KAAI;EAC5B,4BAAA,MAAM,SAAS,GAAG,MAAM,IAAI,GAAG,IAAI,MAAM,IAAI,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAA;8BAChE,MAAM,OAAO,GAAG,CAAC,IAAI,CAAC,MAAM,IAAIC,gBAAW,CAAC,IAAI,CAAC,CAAA;EAEjD,4BAAA,IAAI,CAAC,SAAS,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,eAAe,KAAK,OAAO,EAAE;kCAC3D,MAAM,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,CAAA;kCAE7C,IAAI,UAAU,EAAE;sCACd,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAA;mCAC5C;EAED,gCAAA,MAAM,UAAU,GAAGC,eAAU,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI,CAAC,QAAQ,EAAE;EAC3D,oCAAA,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC;sCACxB,kBAAkB,EAChB,OAAO,IAAI,CAAC,OAAO,CAAC,WAAW,KAAK,UAAU;EAC5C,0CAAE,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC;8CACzB,MAAM,EAAE,IAAI,CAAC,MAAM;8CACnB,IAAI;8CACJ,GAAG;8CACH,SAAS;2CACV,CAAC;EACF,0CAAE,IAAI,CAAC,OAAO,CAAC,WAAW;EAC/B,iCAAA,CAAC,CAAA;EAEF,gCAAA,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;+BAC7B;EAED,4BAAA,OAAO,IAAI,CAAC,OAAO,CAAC,eAAe,CAAA;EACrC,yBAAC,CAAC,CAAA;0BAEF,OAAOC,kBAAa,CAAC,MAAM,CAAC,GAAG,EAAE,WAAW,CAAC,CAAA;uBAC9C;EACF,iBAAA;eACF,CAAC;WACH,CAAA;OACF;EACF,CAAA;;;;;;;;;;;"}
|
|
@@ -34,7 +34,7 @@ declare module '@tiptap/core' {
|
|
|
34
34
|
defaultOptions?: Options;
|
|
35
35
|
/**
|
|
36
36
|
* This method will add options to this extension
|
|
37
|
-
* @see https://tiptap.dev/guide/custom-extensions#settings
|
|
37
|
+
* @see https://tiptap.dev/docs/editor/guide/custom-extensions#settings
|
|
38
38
|
* @example
|
|
39
39
|
* addOptions() {
|
|
40
40
|
* return {
|
|
@@ -48,7 +48,7 @@ declare module '@tiptap/core' {
|
|
|
48
48
|
}) => Options;
|
|
49
49
|
/**
|
|
50
50
|
* The default storage this extension can save data to.
|
|
51
|
-
* @see https://tiptap.dev/guide/custom-extensions#storage
|
|
51
|
+
* @see https://tiptap.dev/docs/editor/guide/custom-extensions#storage
|
|
52
52
|
* @example
|
|
53
53
|
* defaultStorage: {
|
|
54
54
|
* prefetchedUsers: [],
|
|
@@ -62,7 +62,7 @@ declare module '@tiptap/core' {
|
|
|
62
62
|
}) => Storage;
|
|
63
63
|
/**
|
|
64
64
|
* This function adds globalAttributes to specific nodes.
|
|
65
|
-
* @see https://tiptap.dev/guide/custom-extensions#global-attributes
|
|
65
|
+
* @see https://tiptap.dev/docs/editor/guide/custom-extensions#global-attributes
|
|
66
66
|
* @example
|
|
67
67
|
* addGlobalAttributes() {
|
|
68
68
|
* return [
|
|
@@ -95,7 +95,7 @@ declare module '@tiptap/core' {
|
|
|
95
95
|
}) => GlobalAttributes;
|
|
96
96
|
/**
|
|
97
97
|
* This function adds commands to the editor
|
|
98
|
-
* @see https://tiptap.dev/guide/custom-extensions#
|
|
98
|
+
* @see https://tiptap.dev/docs/editor/guide/custom-extensions#commands
|
|
99
99
|
* @example
|
|
100
100
|
* addCommands() {
|
|
101
101
|
* return {
|
|
@@ -112,7 +112,7 @@ declare module '@tiptap/core' {
|
|
|
112
112
|
}) => Partial<RawCommands>;
|
|
113
113
|
/**
|
|
114
114
|
* This function registers keyboard shortcuts.
|
|
115
|
-
* @see https://tiptap.dev/guide/custom-extensions#keyboard-shortcuts
|
|
115
|
+
* @see https://tiptap.dev/docs/editor/guide/custom-extensions#keyboard-shortcuts
|
|
116
116
|
* @example
|
|
117
117
|
* addKeyboardShortcuts() {
|
|
118
118
|
* return {
|
|
@@ -131,7 +131,7 @@ declare module '@tiptap/core' {
|
|
|
131
131
|
};
|
|
132
132
|
/**
|
|
133
133
|
* This function adds input rules to the editor.
|
|
134
|
-
* @see https://tiptap.dev/guide/custom-extensions#input-rules
|
|
134
|
+
* @see https://tiptap.dev/docs/editor/guide/custom-extensions#input-rules
|
|
135
135
|
* @example
|
|
136
136
|
* addInputRules() {
|
|
137
137
|
* return [
|
|
@@ -151,7 +151,7 @@ declare module '@tiptap/core' {
|
|
|
151
151
|
}) => InputRule[];
|
|
152
152
|
/**
|
|
153
153
|
* This function adds paste rules to the editor.
|
|
154
|
-
* @see https://tiptap.dev/guide/custom-extensions#paste-rules
|
|
154
|
+
* @see https://tiptap.dev/docs/editor/guide/custom-extensions#paste-rules
|
|
155
155
|
* @example
|
|
156
156
|
* addPasteRules() {
|
|
157
157
|
* return [
|
|
@@ -171,7 +171,7 @@ declare module '@tiptap/core' {
|
|
|
171
171
|
}) => PasteRule[];
|
|
172
172
|
/**
|
|
173
173
|
* This function adds Prosemirror plugins to the editor
|
|
174
|
-
* @see https://tiptap.dev/guide/custom-extensions#prosemirror-plugins
|
|
174
|
+
* @see https://tiptap.dev/docs/editor/guide/custom-extensions#prosemirror-plugins
|
|
175
175
|
* @example
|
|
176
176
|
* addProseMirrorPlugins() {
|
|
177
177
|
* return [
|
|
@@ -40,6 +40,11 @@ export interface EditorEvents {
|
|
|
40
40
|
editor: Editor;
|
|
41
41
|
transaction: Transaction;
|
|
42
42
|
};
|
|
43
|
+
beforeTransaction: {
|
|
44
|
+
editor: Editor;
|
|
45
|
+
transaction: Transaction;
|
|
46
|
+
nextState: EditorState;
|
|
47
|
+
};
|
|
43
48
|
transaction: {
|
|
44
49
|
editor: Editor;
|
|
45
50
|
transaction: Transaction;
|
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
* Supports numbers, strings and objects.
|
|
4
4
|
*/
|
|
5
5
|
export declare function removeDuplicates<T>(array: T[], by?: {
|
|
6
|
-
(value: any, replacer?: (
|
|
7
|
-
(value: any, replacer?: (
|
|
6
|
+
(value: any, replacer?: (this: any, key: string, value: any) => any, space?: string | number): string;
|
|
7
|
+
(value: any, replacer?: (number | string)[] | null, space?: string | number): string;
|
|
8
8
|
}): T[];
|
|
@@ -23,14 +23,6 @@ export interface PlaceholderOptions {
|
|
|
23
23
|
pos: number;
|
|
24
24
|
hasAnchor: boolean;
|
|
25
25
|
}) => string) | string;
|
|
26
|
-
/**
|
|
27
|
-
* **Used for empty check on the document.**
|
|
28
|
-
*
|
|
29
|
-
* If true, any node that is not a leaf or atom will be considered for empty check.
|
|
30
|
-
* If false, only default nodes (paragraphs) will be considered for empty check.
|
|
31
|
-
* @default false
|
|
32
|
-
*/
|
|
33
|
-
considerAnyAsEmpty: boolean;
|
|
34
26
|
/**
|
|
35
27
|
* **Checks if the placeholder should be only shown when the editor is editable.**
|
|
36
28
|
*
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tiptap/extension-placeholder",
|
|
3
3
|
"description": "placeholder extension for tiptap",
|
|
4
|
-
"version": "2.5.0-
|
|
4
|
+
"version": "2.5.0-pre.10",
|
|
5
5
|
"homepage": "https://tiptap.dev",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"tiptap",
|
|
@@ -29,12 +29,12 @@
|
|
|
29
29
|
"dist"
|
|
30
30
|
],
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"@tiptap/core": "^2.5.0-
|
|
33
|
-
"@tiptap/pm": "^2.5.0-
|
|
32
|
+
"@tiptap/core": "^2.5.0-pre.10",
|
|
33
|
+
"@tiptap/pm": "^2.5.0-pre.10"
|
|
34
34
|
},
|
|
35
35
|
"peerDependencies": {
|
|
36
|
-
"@tiptap/core": "^2.0.
|
|
37
|
-
"@tiptap/pm": "^2.0.
|
|
36
|
+
"@tiptap/core": "^2.5.0-pre.10",
|
|
37
|
+
"@tiptap/pm": "^2.5.0-pre.10"
|
|
38
38
|
},
|
|
39
39
|
"repository": {
|
|
40
40
|
"type": "git",
|
package/src/placeholder.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Editor, Extension } from '@tiptap/core'
|
|
1
|
+
import { Editor, Extension, isNodeEmpty } from '@tiptap/core'
|
|
2
2
|
import { Node as ProsemirrorNode } from '@tiptap/pm/model'
|
|
3
3
|
import { Plugin, PluginKey } from '@tiptap/pm/state'
|
|
4
4
|
import { Decoration, DecorationSet } from '@tiptap/pm/view'
|
|
@@ -31,15 +31,6 @@ export interface PlaceholderOptions {
|
|
|
31
31
|
}) => string)
|
|
32
32
|
| string
|
|
33
33
|
|
|
34
|
-
/**
|
|
35
|
-
* **Used for empty check on the document.**
|
|
36
|
-
*
|
|
37
|
-
* If true, any node that is not a leaf or atom will be considered for empty check.
|
|
38
|
-
* If false, only default nodes (paragraphs) will be considered for empty check.
|
|
39
|
-
* @default false
|
|
40
|
-
*/
|
|
41
|
-
considerAnyAsEmpty: boolean
|
|
42
|
-
|
|
43
34
|
/**
|
|
44
35
|
* **Checks if the placeholder should be only shown when the editor is editable.**
|
|
45
36
|
*
|
|
@@ -82,7 +73,6 @@ export const Placeholder = Extension.create<PlaceholderOptions>({
|
|
|
82
73
|
emptyNodeClass: 'is-empty',
|
|
83
74
|
placeholder: 'Write something …',
|
|
84
75
|
showOnlyWhenEditable: true,
|
|
85
|
-
considerAnyAsEmpty: false,
|
|
86
76
|
showOnlyCurrent: true,
|
|
87
77
|
includeChildren: false,
|
|
88
78
|
}
|
|
@@ -102,21 +92,11 @@ export const Placeholder = Extension.create<PlaceholderOptions>({
|
|
|
102
92
|
return null
|
|
103
93
|
}
|
|
104
94
|
|
|
105
|
-
|
|
106
|
-
const { firstChild } = doc.content
|
|
107
|
-
const isLeaf = firstChild && firstChild.type.isLeaf
|
|
108
|
-
const isAtom = firstChild && firstChild.isAtom
|
|
109
|
-
const isValidNode = this.options.considerAnyAsEmpty
|
|
110
|
-
? true
|
|
111
|
-
: firstChild && firstChild.type.name === doc.type.contentMatch.defaultType?.name
|
|
112
|
-
const isEmptyDoc = doc.content.childCount <= 1
|
|
113
|
-
&& firstChild
|
|
114
|
-
&& isValidNode
|
|
115
|
-
&& (firstChild.nodeSize <= 2 && (!isLeaf || !isAtom))
|
|
95
|
+
const isEmptyDoc = this.editor.isEmpty
|
|
116
96
|
|
|
117
97
|
doc.descendants((node, pos) => {
|
|
118
98
|
const hasAnchor = anchor >= pos && anchor <= pos + node.nodeSize
|
|
119
|
-
const isEmpty = !node.isLeaf &&
|
|
99
|
+
const isEmpty = !node.isLeaf && isNodeEmpty(node)
|
|
120
100
|
|
|
121
101
|
if ((hasAnchor || !this.options.showOnlyCurrent) && isEmpty) {
|
|
122
102
|
const classes = [this.options.emptyNodeClass]
|