@kopexa/editor-utils 17.1.9 → 17.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-TZDBVEXH.mjs +30 -0
- package/dist/hooks/use-is-editor-empty.d.mts +15 -0
- package/dist/hooks/use-is-editor-empty.d.ts +15 -0
- package/dist/hooks/use-is-editor-empty.js +54 -0
- package/dist/hooks/use-is-editor-empty.mjs +8 -0
- package/dist/index.d.mts +7 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.js +40 -5
- package/dist/index.mjs +11 -0
- package/package.json +4 -4
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/hooks/use-is-editor-empty.ts
|
|
4
|
+
import { useCurrentEditor, useEditorState } from "@tiptap/react";
|
|
5
|
+
import { useMemo } from "react";
|
|
6
|
+
function useIsEditorEmpty(providedEditor) {
|
|
7
|
+
const { editor: coreEditor } = useCurrentEditor();
|
|
8
|
+
const mainEditor = useMemo(
|
|
9
|
+
() => providedEditor || coreEditor,
|
|
10
|
+
[providedEditor, coreEditor]
|
|
11
|
+
);
|
|
12
|
+
const isEmpty = useEditorState({
|
|
13
|
+
editor: mainEditor,
|
|
14
|
+
selector(context) {
|
|
15
|
+
if (!context.editor) {
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
if (context.editor.isEmpty) {
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
const text = context.editor.state.doc.textContent;
|
|
22
|
+
return text.trim().length === 0;
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
return isEmpty != null ? isEmpty : true;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export {
|
|
29
|
+
useIsEditorEmpty
|
|
30
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Editor } from '@tiptap/react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Hook that reactively tracks whether the editor is effectively empty.
|
|
5
|
+
* This considers documents with only whitespace as empty.
|
|
6
|
+
*
|
|
7
|
+
* Unlike a static check, this hook re-renders when the content changes,
|
|
8
|
+
* making it suitable for conditional rendering based on empty state.
|
|
9
|
+
*
|
|
10
|
+
* @param providedEditor - Optional editor instance to use instead of the context editor
|
|
11
|
+
* @returns boolean indicating if the editor is effectively empty
|
|
12
|
+
*/
|
|
13
|
+
declare function useIsEditorEmpty(providedEditor?: Editor | null): boolean;
|
|
14
|
+
|
|
15
|
+
export { useIsEditorEmpty };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Editor } from '@tiptap/react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Hook that reactively tracks whether the editor is effectively empty.
|
|
5
|
+
* This considers documents with only whitespace as empty.
|
|
6
|
+
*
|
|
7
|
+
* Unlike a static check, this hook re-renders when the content changes,
|
|
8
|
+
* making it suitable for conditional rendering based on empty state.
|
|
9
|
+
*
|
|
10
|
+
* @param providedEditor - Optional editor instance to use instead of the context editor
|
|
11
|
+
* @returns boolean indicating if the editor is effectively empty
|
|
12
|
+
*/
|
|
13
|
+
declare function useIsEditorEmpty(providedEditor?: Editor | null): boolean;
|
|
14
|
+
|
|
15
|
+
export { useIsEditorEmpty };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use strict";
|
|
3
|
+
"use client";
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
21
|
+
|
|
22
|
+
// src/hooks/use-is-editor-empty.ts
|
|
23
|
+
var use_is_editor_empty_exports = {};
|
|
24
|
+
__export(use_is_editor_empty_exports, {
|
|
25
|
+
useIsEditorEmpty: () => useIsEditorEmpty
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(use_is_editor_empty_exports);
|
|
28
|
+
var import_react = require("@tiptap/react");
|
|
29
|
+
var import_react2 = require("react");
|
|
30
|
+
function useIsEditorEmpty(providedEditor) {
|
|
31
|
+
const { editor: coreEditor } = (0, import_react.useCurrentEditor)();
|
|
32
|
+
const mainEditor = (0, import_react2.useMemo)(
|
|
33
|
+
() => providedEditor || coreEditor,
|
|
34
|
+
[providedEditor, coreEditor]
|
|
35
|
+
);
|
|
36
|
+
const isEmpty = (0, import_react.useEditorState)({
|
|
37
|
+
editor: mainEditor,
|
|
38
|
+
selector(context) {
|
|
39
|
+
if (!context.editor) {
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
if (context.editor.isEmpty) {
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
const text = context.editor.state.doc.textContent;
|
|
46
|
+
return text.trim().length === 0;
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
return isEmpty != null ? isEmpty : true;
|
|
50
|
+
}
|
|
51
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
52
|
+
0 && (module.exports = {
|
|
53
|
+
useIsEditorEmpty
|
|
54
|
+
});
|
package/dist/index.d.mts
CHANGED
|
@@ -2,6 +2,7 @@ import * as _tiptap_core from '@tiptap/core';
|
|
|
2
2
|
import { Node, Attrs } from '@tiptap/pm/model';
|
|
3
3
|
import { Selection } from '@tiptap/pm/state';
|
|
4
4
|
import { Editor } from '@tiptap/react';
|
|
5
|
+
export { useIsEditorEmpty } from './hooks/use-is-editor-empty.mjs';
|
|
5
6
|
export { useTiptapEditor } from './hooks/use-tiptap-editor.mjs';
|
|
6
7
|
export { getSelectedBlockNodes, getSelectedNodesOfType, selectionWithinConvertibleTypes } from './selection.mjs';
|
|
7
8
|
export { updateNodesAttr } from './update-node-attrs.mjs';
|
|
@@ -47,6 +48,11 @@ declare function getActiveMarkAttrs(editor: Editor | null, markName: string): At
|
|
|
47
48
|
* Checks if a node is empty
|
|
48
49
|
*/
|
|
49
50
|
declare function isEmptyNode(node?: Node | null): boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Checks if an editor is effectively empty (empty or contains only whitespace).
|
|
53
|
+
* This considers documents with only spaces, tabs, or newlines as empty.
|
|
54
|
+
*/
|
|
55
|
+
declare function isEditorEffectivelyEmpty(editor: Editor | null): boolean;
|
|
50
56
|
/**
|
|
51
57
|
* Finds the position and instance of a node in the document
|
|
52
58
|
* @param props Object containing editor, node (optional), and nodePos (optional)
|
|
@@ -102,4 +108,4 @@ declare function findSelectionPosition(params: {
|
|
|
102
108
|
nodePos?: number | null;
|
|
103
109
|
}): number | null;
|
|
104
110
|
|
|
105
|
-
export { type OverflowPosition, findNodePosition, findParentNodeOfType, findSelectionPosition, getActiveMarkAttrs, getEditorExtension, getElementOverflowPosition, hasContentAbove, isEmptyNode, isExtensionAvailable, isMarkInSchema, isNodeInSchema, isNodeTypeSelected, isValidPosition };
|
|
111
|
+
export { type OverflowPosition, findNodePosition, findParentNodeOfType, findSelectionPosition, getActiveMarkAttrs, getEditorExtension, getElementOverflowPosition, hasContentAbove, isEditorEffectivelyEmpty, isEmptyNode, isExtensionAvailable, isMarkInSchema, isNodeInSchema, isNodeTypeSelected, isValidPosition };
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import * as _tiptap_core from '@tiptap/core';
|
|
|
2
2
|
import { Node, Attrs } from '@tiptap/pm/model';
|
|
3
3
|
import { Selection } from '@tiptap/pm/state';
|
|
4
4
|
import { Editor } from '@tiptap/react';
|
|
5
|
+
export { useIsEditorEmpty } from './hooks/use-is-editor-empty.js';
|
|
5
6
|
export { useTiptapEditor } from './hooks/use-tiptap-editor.js';
|
|
6
7
|
export { getSelectedBlockNodes, getSelectedNodesOfType, selectionWithinConvertibleTypes } from './selection.js';
|
|
7
8
|
export { updateNodesAttr } from './update-node-attrs.js';
|
|
@@ -47,6 +48,11 @@ declare function getActiveMarkAttrs(editor: Editor | null, markName: string): At
|
|
|
47
48
|
* Checks if a node is empty
|
|
48
49
|
*/
|
|
49
50
|
declare function isEmptyNode(node?: Node | null): boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Checks if an editor is effectively empty (empty or contains only whitespace).
|
|
53
|
+
* This considers documents with only spaces, tabs, or newlines as empty.
|
|
54
|
+
*/
|
|
55
|
+
declare function isEditorEffectivelyEmpty(editor: Editor | null): boolean;
|
|
50
56
|
/**
|
|
51
57
|
* Finds the position and instance of a node in the document
|
|
52
58
|
* @param props Object containing editor, node (optional), and nodePos (optional)
|
|
@@ -102,4 +108,4 @@ declare function findSelectionPosition(params: {
|
|
|
102
108
|
nodePos?: number | null;
|
|
103
109
|
}): number | null;
|
|
104
110
|
|
|
105
|
-
export { type OverflowPosition, findNodePosition, findParentNodeOfType, findSelectionPosition, getActiveMarkAttrs, getEditorExtension, getElementOverflowPosition, hasContentAbove, isEmptyNode, isExtensionAvailable, isMarkInSchema, isNodeInSchema, isNodeTypeSelected, isValidPosition };
|
|
111
|
+
export { type OverflowPosition, findNodePosition, findParentNodeOfType, findSelectionPosition, getActiveMarkAttrs, getEditorExtension, getElementOverflowPosition, hasContentAbove, isEditorEffectivelyEmpty, isEmptyNode, isExtensionAvailable, isMarkInSchema, isNodeInSchema, isNodeTypeSelected, isValidPosition };
|
package/dist/index.js
CHANGED
|
@@ -30,6 +30,7 @@ __export(index_exports, {
|
|
|
30
30
|
getSelectedBlockNodes: () => getSelectedBlockNodes,
|
|
31
31
|
getSelectedNodesOfType: () => getSelectedNodesOfType,
|
|
32
32
|
hasContentAbove: () => hasContentAbove,
|
|
33
|
+
isEditorEffectivelyEmpty: () => isEditorEffectivelyEmpty,
|
|
33
34
|
isEmptyNode: () => isEmptyNode,
|
|
34
35
|
isExtensionAvailable: () => isExtensionAvailable,
|
|
35
36
|
isMarkInSchema: () => isMarkInSchema,
|
|
@@ -38,21 +39,47 @@ __export(index_exports, {
|
|
|
38
39
|
isValidPosition: () => isValidPosition,
|
|
39
40
|
selectionWithinConvertibleTypes: () => selectionWithinConvertibleTypes,
|
|
40
41
|
updateNodesAttr: () => updateNodesAttr,
|
|
42
|
+
useIsEditorEmpty: () => useIsEditorEmpty,
|
|
41
43
|
useTiptapEditor: () => useTiptapEditor
|
|
42
44
|
});
|
|
43
45
|
module.exports = __toCommonJS(index_exports);
|
|
44
46
|
var import_state2 = require("@tiptap/pm/state");
|
|
45
47
|
|
|
46
|
-
// src/hooks/use-
|
|
48
|
+
// src/hooks/use-is-editor-empty.ts
|
|
47
49
|
var import_react = require("@tiptap/react");
|
|
48
50
|
var import_react2 = require("react");
|
|
49
|
-
function
|
|
51
|
+
function useIsEditorEmpty(providedEditor) {
|
|
50
52
|
const { editor: coreEditor } = (0, import_react.useCurrentEditor)();
|
|
51
53
|
const mainEditor = (0, import_react2.useMemo)(
|
|
52
54
|
() => providedEditor || coreEditor,
|
|
53
55
|
[providedEditor, coreEditor]
|
|
54
56
|
);
|
|
55
|
-
const
|
|
57
|
+
const isEmpty = (0, import_react.useEditorState)({
|
|
58
|
+
editor: mainEditor,
|
|
59
|
+
selector(context) {
|
|
60
|
+
if (!context.editor) {
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
if (context.editor.isEmpty) {
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
const text = context.editor.state.doc.textContent;
|
|
67
|
+
return text.trim().length === 0;
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
return isEmpty != null ? isEmpty : true;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// src/hooks/use-tiptap-editor.ts
|
|
74
|
+
var import_react3 = require("@tiptap/react");
|
|
75
|
+
var import_react4 = require("react");
|
|
76
|
+
function useTiptapEditor(providedEditor) {
|
|
77
|
+
const { editor: coreEditor } = (0, import_react3.useCurrentEditor)();
|
|
78
|
+
const mainEditor = (0, import_react4.useMemo)(
|
|
79
|
+
() => providedEditor || coreEditor,
|
|
80
|
+
[providedEditor, coreEditor]
|
|
81
|
+
);
|
|
82
|
+
const editorState = (0, import_react3.useEditorState)({
|
|
56
83
|
editor: mainEditor,
|
|
57
84
|
selector(context) {
|
|
58
85
|
if (!context.editor) {
|
|
@@ -75,7 +102,7 @@ function useTiptapEditor(providedEditor) {
|
|
|
75
102
|
// src/selection.ts
|
|
76
103
|
var import_state = require("@tiptap/pm/state");
|
|
77
104
|
var import_tables = require("@tiptap/pm/tables");
|
|
78
|
-
var
|
|
105
|
+
var import_react5 = require("@tiptap/react");
|
|
79
106
|
function getSelectedBlockNodes(editor) {
|
|
80
107
|
const { doc } = editor.state;
|
|
81
108
|
const { from, to } = editor.state.selection;
|
|
@@ -118,7 +145,7 @@ function getSelectedNodesOfType(selection, allowedNodeTypes) {
|
|
|
118
145
|
return results;
|
|
119
146
|
}
|
|
120
147
|
}
|
|
121
|
-
const parentNode = (0,
|
|
148
|
+
const parentNode = (0, import_react5.findParentNodeClosestToPos)(
|
|
122
149
|
$anchor,
|
|
123
150
|
(node) => allowed.has(node.type.name)
|
|
124
151
|
);
|
|
@@ -217,6 +244,12 @@ function getActiveMarkAttrs(editor, markName) {
|
|
|
217
244
|
function isEmptyNode(node) {
|
|
218
245
|
return !!node && node.content.size === 0;
|
|
219
246
|
}
|
|
247
|
+
function isEditorEffectivelyEmpty(editor) {
|
|
248
|
+
if (!editor) return true;
|
|
249
|
+
if (editor.isEmpty) return true;
|
|
250
|
+
const text = editor.state.doc.textContent;
|
|
251
|
+
return text.trim().length === 0;
|
|
252
|
+
}
|
|
220
253
|
function findNodePosition(props) {
|
|
221
254
|
var _a;
|
|
222
255
|
const { editor, node, nodePos } = props;
|
|
@@ -318,6 +351,7 @@ function findSelectionPosition(params) {
|
|
|
318
351
|
getSelectedBlockNodes,
|
|
319
352
|
getSelectedNodesOfType,
|
|
320
353
|
hasContentAbove,
|
|
354
|
+
isEditorEffectivelyEmpty,
|
|
321
355
|
isEmptyNode,
|
|
322
356
|
isExtensionAvailable,
|
|
323
357
|
isMarkInSchema,
|
|
@@ -326,5 +360,6 @@ function findSelectionPosition(params) {
|
|
|
326
360
|
isValidPosition,
|
|
327
361
|
selectionWithinConvertibleTypes,
|
|
328
362
|
updateNodesAttr,
|
|
363
|
+
useIsEditorEmpty,
|
|
329
364
|
useTiptapEditor
|
|
330
365
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -7,6 +7,9 @@ import {
|
|
|
7
7
|
import {
|
|
8
8
|
updateNodesAttr
|
|
9
9
|
} from "./chunk-23NZ6BRW.mjs";
|
|
10
|
+
import {
|
|
11
|
+
useIsEditorEmpty
|
|
12
|
+
} from "./chunk-TZDBVEXH.mjs";
|
|
10
13
|
import {
|
|
11
14
|
useTiptapEditor
|
|
12
15
|
} from "./chunk-P55PLOHR.mjs";
|
|
@@ -56,6 +59,12 @@ function getActiveMarkAttrs(editor, markName) {
|
|
|
56
59
|
function isEmptyNode(node) {
|
|
57
60
|
return !!node && node.content.size === 0;
|
|
58
61
|
}
|
|
62
|
+
function isEditorEffectivelyEmpty(editor) {
|
|
63
|
+
if (!editor) return true;
|
|
64
|
+
if (editor.isEmpty) return true;
|
|
65
|
+
const text = editor.state.doc.textContent;
|
|
66
|
+
return text.trim().length === 0;
|
|
67
|
+
}
|
|
59
68
|
function findNodePosition(props) {
|
|
60
69
|
var _a;
|
|
61
70
|
const { editor, node, nodePos } = props;
|
|
@@ -156,6 +165,7 @@ export {
|
|
|
156
165
|
getSelectedBlockNodes,
|
|
157
166
|
getSelectedNodesOfType,
|
|
158
167
|
hasContentAbove,
|
|
168
|
+
isEditorEffectivelyEmpty,
|
|
159
169
|
isEmptyNode,
|
|
160
170
|
isExtensionAvailable,
|
|
161
171
|
isMarkInSchema,
|
|
@@ -164,5 +174,6 @@ export {
|
|
|
164
174
|
isValidPosition,
|
|
165
175
|
selectionWithinConvertibleTypes,
|
|
166
176
|
updateNodesAttr,
|
|
177
|
+
useIsEditorEmpty,
|
|
167
178
|
useTiptapEditor
|
|
168
179
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kopexa/editor-utils",
|
|
3
|
-
"version": "17.
|
|
3
|
+
"version": "17.2.0",
|
|
4
4
|
"description": "utility components for our editor",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"editor-utils"
|
|
@@ -30,11 +30,11 @@
|
|
|
30
30
|
"motion": ">=12.23.6",
|
|
31
31
|
"react": ">=19.0.0-rc.0",
|
|
32
32
|
"react-dom": ">=19.0.0-rc.0",
|
|
33
|
-
"@kopexa/theme": "17.
|
|
33
|
+
"@kopexa/theme": "17.25.0"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@kopexa/react-utils": "17.1.
|
|
37
|
-
"@kopexa/shared-utils": "17.0.
|
|
36
|
+
"@kopexa/react-utils": "17.1.1",
|
|
37
|
+
"@kopexa/shared-utils": "17.0.59"
|
|
38
38
|
},
|
|
39
39
|
"clean-package": "../../../clean-package.config.json",
|
|
40
40
|
"module": "dist/index.mjs",
|