@kopexa/editor-utils 17.0.48 → 17.1.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.
@@ -0,0 +1,90 @@
1
+ "use client";
2
+
3
+ // src/selection.ts
4
+ import {
5
+ AllSelection,
6
+ NodeSelection,
7
+ TextSelection
8
+ } from "@tiptap/pm/state";
9
+ import { CellSelection, cellAround } from "@tiptap/pm/tables";
10
+ import { findParentNodeClosestToPos } from "@tiptap/react";
11
+ function getSelectedBlockNodes(editor) {
12
+ const { doc } = editor.state;
13
+ const { from, to } = editor.state.selection;
14
+ const blocks = [];
15
+ const seen = /* @__PURE__ */ new Set();
16
+ doc.nodesBetween(from, to, (node, pos) => {
17
+ if (!node.isBlock) return;
18
+ if (!seen.has(pos)) {
19
+ seen.add(pos);
20
+ blocks.push(node);
21
+ }
22
+ return false;
23
+ });
24
+ return blocks;
25
+ }
26
+ function getSelectedNodesOfType(selection, allowedNodeTypes) {
27
+ const results = [];
28
+ const allowed = new Set(allowedNodeTypes);
29
+ if (selection instanceof CellSelection) {
30
+ selection.forEachCell((node, pos) => {
31
+ if (allowed.has(node.type.name)) {
32
+ results.push({ node, pos });
33
+ }
34
+ });
35
+ return results;
36
+ }
37
+ if (selection instanceof NodeSelection) {
38
+ const { node, from: pos } = selection;
39
+ if (node && allowed.has(node.type.name)) {
40
+ results.push({ node, pos });
41
+ }
42
+ return results;
43
+ }
44
+ const { $anchor } = selection;
45
+ const cell = cellAround($anchor);
46
+ if (cell) {
47
+ const cellNode = selection.$anchor.doc.nodeAt(cell.pos);
48
+ if (cellNode && allowed.has(cellNode.type.name)) {
49
+ results.push({ node: cellNode, pos: cell.pos });
50
+ return results;
51
+ }
52
+ }
53
+ const parentNode = findParentNodeClosestToPos(
54
+ $anchor,
55
+ (node) => allowed.has(node.type.name)
56
+ );
57
+ if (parentNode) {
58
+ results.push({ node: parentNode.node, pos: parentNode.pos });
59
+ }
60
+ return results;
61
+ }
62
+ function selectionWithinConvertibleTypes(editor, types = []) {
63
+ var _a, _b;
64
+ if (!editor || types.length === 0) return false;
65
+ const { state } = editor;
66
+ const { selection } = state;
67
+ const allowed = new Set(types);
68
+ if (selection instanceof NodeSelection) {
69
+ const nodeType = (_b = (_a = selection.node) == null ? void 0 : _a.type) == null ? void 0 : _b.name;
70
+ return !!nodeType && allowed.has(nodeType);
71
+ }
72
+ if (selection instanceof TextSelection || selection instanceof AllSelection) {
73
+ let valid = true;
74
+ state.doc.nodesBetween(selection.from, selection.to, (node) => {
75
+ if (node.isTextblock && !allowed.has(node.type.name)) {
76
+ valid = false;
77
+ return false;
78
+ }
79
+ return valid;
80
+ });
81
+ return valid;
82
+ }
83
+ return false;
84
+ }
85
+
86
+ export {
87
+ getSelectedBlockNodes,
88
+ getSelectedNodesOfType,
89
+ selectionWithinConvertibleTypes
90
+ };
package/dist/index.d.mts CHANGED
@@ -2,8 +2,8 @@ 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 { getSelectedNodesOfType } from './get-selected-nodes-of-type.mjs';
6
5
  export { useTiptapEditor } from './hooks/use-tiptap-editor.mjs';
6
+ export { getSelectedBlockNodes, getSelectedNodesOfType, selectionWithinConvertibleTypes } from './selection.mjs';
7
7
  export { updateNodesAttr } from './update-node-attrs.mjs';
8
8
 
9
9
  type OverflowPosition = "none" | "top" | "bottom" | "both";
package/dist/index.d.ts CHANGED
@@ -2,8 +2,8 @@ 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 { getSelectedNodesOfType } from './get-selected-nodes-of-type.js';
6
5
  export { useTiptapEditor } from './hooks/use-tiptap-editor.js';
6
+ export { getSelectedBlockNodes, getSelectedNodesOfType, selectionWithinConvertibleTypes } from './selection.js';
7
7
  export { updateNodesAttr } from './update-node-attrs.js';
8
8
 
9
9
  type OverflowPosition = "none" | "top" | "bottom" | "both";
package/dist/index.js CHANGED
@@ -27,6 +27,7 @@ __export(index_exports, {
27
27
  getActiveMarkAttrs: () => getActiveMarkAttrs,
28
28
  getEditorExtension: () => getEditorExtension,
29
29
  getElementOverflowPosition: () => getElementOverflowPosition,
30
+ getSelectedBlockNodes: () => getSelectedBlockNodes,
30
31
  getSelectedNodesOfType: () => getSelectedNodesOfType,
31
32
  hasContentAbove: () => hasContentAbove,
32
33
  isEmptyNode: () => isEmptyNode,
@@ -35,16 +36,61 @@ __export(index_exports, {
35
36
  isNodeInSchema: () => isNodeInSchema,
36
37
  isNodeTypeSelected: () => isNodeTypeSelected,
37
38
  isValidPosition: () => isValidPosition,
39
+ selectionWithinConvertibleTypes: () => selectionWithinConvertibleTypes,
38
40
  updateNodesAttr: () => updateNodesAttr,
39
41
  useTiptapEditor: () => useTiptapEditor
40
42
  });
41
43
  module.exports = __toCommonJS(index_exports);
42
44
  var import_state2 = require("@tiptap/pm/state");
43
45
 
44
- // src/get-selected-nodes-of-type.ts
46
+ // src/hooks/use-tiptap-editor.ts
47
+ var import_react = require("@tiptap/react");
48
+ var import_react2 = require("react");
49
+ function useTiptapEditor(providedEditor) {
50
+ const { editor: coreEditor } = (0, import_react.useCurrentEditor)();
51
+ const mainEditor = (0, import_react2.useMemo)(
52
+ () => providedEditor || coreEditor,
53
+ [providedEditor, coreEditor]
54
+ );
55
+ const editorState = (0, import_react.useEditorState)({
56
+ editor: mainEditor,
57
+ selector(context) {
58
+ if (!context.editor) {
59
+ return {
60
+ editor: null,
61
+ editorState: void 0,
62
+ canCommand: void 0
63
+ };
64
+ }
65
+ return {
66
+ editor: context.editor,
67
+ editorState: context.editor.state,
68
+ canCommand: context.editor.can
69
+ };
70
+ }
71
+ });
72
+ return editorState || { editor: null };
73
+ }
74
+
75
+ // src/selection.ts
45
76
  var import_state = require("@tiptap/pm/state");
46
77
  var import_tables = require("@tiptap/pm/tables");
47
- var import_react = require("@tiptap/react");
78
+ var import_react3 = require("@tiptap/react");
79
+ function getSelectedBlockNodes(editor) {
80
+ const { doc } = editor.state;
81
+ const { from, to } = editor.state.selection;
82
+ const blocks = [];
83
+ const seen = /* @__PURE__ */ new Set();
84
+ doc.nodesBetween(from, to, (node, pos) => {
85
+ if (!node.isBlock) return;
86
+ if (!seen.has(pos)) {
87
+ seen.add(pos);
88
+ blocks.push(node);
89
+ }
90
+ return false;
91
+ });
92
+ return blocks;
93
+ }
48
94
  function getSelectedNodesOfType(selection, allowedNodeTypes) {
49
95
  const results = [];
50
96
  const allowed = new Set(allowedNodeTypes);
@@ -72,7 +118,7 @@ function getSelectedNodesOfType(selection, allowedNodeTypes) {
72
118
  return results;
73
119
  }
74
120
  }
75
- const parentNode = (0, import_react.findParentNodeClosestToPos)(
121
+ const parentNode = (0, import_react3.findParentNodeClosestToPos)(
76
122
  $anchor,
77
123
  (node) => allowed.has(node.type.name)
78
124
  );
@@ -81,34 +127,28 @@ function getSelectedNodesOfType(selection, allowedNodeTypes) {
81
127
  }
82
128
  return results;
83
129
  }
84
-
85
- // src/hooks/use-tiptap-editor.ts
86
- var import_react2 = require("@tiptap/react");
87
- var import_react3 = require("react");
88
- function useTiptapEditor(providedEditor) {
89
- const { editor: coreEditor } = (0, import_react2.useCurrentEditor)();
90
- const mainEditor = (0, import_react3.useMemo)(
91
- () => providedEditor || coreEditor,
92
- [providedEditor, coreEditor]
93
- );
94
- const editorState = (0, import_react2.useEditorState)({
95
- editor: mainEditor,
96
- selector(context) {
97
- if (!context.editor) {
98
- return {
99
- editor: null,
100
- editorState: void 0,
101
- canCommand: void 0
102
- };
130
+ function selectionWithinConvertibleTypes(editor, types = []) {
131
+ var _a, _b;
132
+ if (!editor || types.length === 0) return false;
133
+ const { state } = editor;
134
+ const { selection } = state;
135
+ const allowed = new Set(types);
136
+ if (selection instanceof import_state.NodeSelection) {
137
+ const nodeType = (_b = (_a = selection.node) == null ? void 0 : _a.type) == null ? void 0 : _b.name;
138
+ return !!nodeType && allowed.has(nodeType);
139
+ }
140
+ if (selection instanceof import_state.TextSelection || selection instanceof import_state.AllSelection) {
141
+ let valid = true;
142
+ state.doc.nodesBetween(selection.from, selection.to, (node) => {
143
+ if (node.isTextblock && !allowed.has(node.type.name)) {
144
+ valid = false;
145
+ return false;
103
146
  }
104
- return {
105
- editor: context.editor,
106
- editorState: context.editor.state,
107
- canCommand: context.editor.can
108
- };
109
- }
110
- });
111
- return editorState || { editor: null };
147
+ return valid;
148
+ });
149
+ return valid;
150
+ }
151
+ return false;
112
152
  }
113
153
 
114
154
  // src/update-node-attrs.ts
@@ -281,6 +321,7 @@ function findSelectionPosition(params) {
281
321
  getActiveMarkAttrs,
282
322
  getEditorExtension,
283
323
  getElementOverflowPosition,
324
+ getSelectedBlockNodes,
284
325
  getSelectedNodesOfType,
285
326
  hasContentAbove,
286
327
  isEmptyNode,
@@ -289,6 +330,7 @@ function findSelectionPosition(params) {
289
330
  isNodeInSchema,
290
331
  isNodeTypeSelected,
291
332
  isValidPosition,
333
+ selectionWithinConvertibleTypes,
292
334
  updateNodesAttr,
293
335
  useTiptapEditor
294
336
  });
package/dist/index.mjs CHANGED
@@ -1,7 +1,9 @@
1
1
  "use client";
2
2
  import {
3
- getSelectedNodesOfType
4
- } from "./chunk-EGCOGZWA.mjs";
3
+ getSelectedBlockNodes,
4
+ getSelectedNodesOfType,
5
+ selectionWithinConvertibleTypes
6
+ } from "./chunk-ID5T7EEZ.mjs";
5
7
  import {
6
8
  updateNodesAttr
7
9
  } from "./chunk-23NZ6BRW.mjs";
@@ -157,6 +159,7 @@ export {
157
159
  getActiveMarkAttrs,
158
160
  getEditorExtension,
159
161
  getElementOverflowPosition,
162
+ getSelectedBlockNodes,
160
163
  getSelectedNodesOfType,
161
164
  hasContentAbove,
162
165
  isEmptyNode,
@@ -165,6 +168,7 @@ export {
165
168
  isNodeInSchema,
166
169
  isNodeTypeSelected,
167
170
  isValidPosition,
171
+ selectionWithinConvertibleTypes,
168
172
  updateNodesAttr,
169
173
  useTiptapEditor
170
174
  };
@@ -0,0 +1,22 @@
1
+ import { Node } from '@tiptap/pm/model';
2
+ import { Selection } from '@tiptap/pm/state';
3
+ import { Editor, NodeWithPos } from '@tiptap/react';
4
+
5
+ declare function getSelectedBlockNodes(editor: Editor): Node[];
6
+ /**
7
+ * Retrieves all nodes of specified types from the current selection.
8
+ * @param selection The current editor selection
9
+ * @param allowedNodeTypes An array of node type names to look for (e.g., ["image", "table"])
10
+ * @returns An array of objects containing the node and its position
11
+ */
12
+ declare function getSelectedNodesOfType(selection: Selection, allowedNodeTypes: string[]): NodeWithPos[];
13
+ /**
14
+ * Check whether the current selection is fully within nodes
15
+ * whose type names are in the provided `types` list.
16
+ *
17
+ * - NodeSelection → checks the selected node.
18
+ * - Text/AllSelection → ensures all textblocks within [from, to) are allowed.
19
+ */
20
+ declare function selectionWithinConvertibleTypes(editor: Editor, types?: string[]): boolean;
21
+
22
+ export { getSelectedBlockNodes, getSelectedNodesOfType, selectionWithinConvertibleTypes };
@@ -0,0 +1,22 @@
1
+ import { Node } from '@tiptap/pm/model';
2
+ import { Selection } from '@tiptap/pm/state';
3
+ import { Editor, NodeWithPos } from '@tiptap/react';
4
+
5
+ declare function getSelectedBlockNodes(editor: Editor): Node[];
6
+ /**
7
+ * Retrieves all nodes of specified types from the current selection.
8
+ * @param selection The current editor selection
9
+ * @param allowedNodeTypes An array of node type names to look for (e.g., ["image", "table"])
10
+ * @returns An array of objects containing the node and its position
11
+ */
12
+ declare function getSelectedNodesOfType(selection: Selection, allowedNodeTypes: string[]): NodeWithPos[];
13
+ /**
14
+ * Check whether the current selection is fully within nodes
15
+ * whose type names are in the provided `types` list.
16
+ *
17
+ * - NodeSelection → checks the selected node.
18
+ * - Text/AllSelection → ensures all textblocks within [from, to) are allowed.
19
+ */
20
+ declare function selectionWithinConvertibleTypes(editor: Editor, types?: string[]): boolean;
21
+
22
+ export { getSelectedBlockNodes, getSelectedNodesOfType, selectionWithinConvertibleTypes };
@@ -18,15 +18,32 @@ var __copyProps = (to, from, except, desc) => {
18
18
  };
19
19
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
20
 
21
- // src/get-selected-nodes-of-type.ts
22
- var get_selected_nodes_of_type_exports = {};
23
- __export(get_selected_nodes_of_type_exports, {
24
- getSelectedNodesOfType: () => getSelectedNodesOfType
21
+ // src/selection.ts
22
+ var selection_exports = {};
23
+ __export(selection_exports, {
24
+ getSelectedBlockNodes: () => getSelectedBlockNodes,
25
+ getSelectedNodesOfType: () => getSelectedNodesOfType,
26
+ selectionWithinConvertibleTypes: () => selectionWithinConvertibleTypes
25
27
  });
26
- module.exports = __toCommonJS(get_selected_nodes_of_type_exports);
28
+ module.exports = __toCommonJS(selection_exports);
27
29
  var import_state = require("@tiptap/pm/state");
28
30
  var import_tables = require("@tiptap/pm/tables");
29
31
  var import_react = require("@tiptap/react");
32
+ function getSelectedBlockNodes(editor) {
33
+ const { doc } = editor.state;
34
+ const { from, to } = editor.state.selection;
35
+ const blocks = [];
36
+ const seen = /* @__PURE__ */ new Set();
37
+ doc.nodesBetween(from, to, (node, pos) => {
38
+ if (!node.isBlock) return;
39
+ if (!seen.has(pos)) {
40
+ seen.add(pos);
41
+ blocks.push(node);
42
+ }
43
+ return false;
44
+ });
45
+ return blocks;
46
+ }
30
47
  function getSelectedNodesOfType(selection, allowedNodeTypes) {
31
48
  const results = [];
32
49
  const allowed = new Set(allowedNodeTypes);
@@ -63,7 +80,32 @@ function getSelectedNodesOfType(selection, allowedNodeTypes) {
63
80
  }
64
81
  return results;
65
82
  }
83
+ function selectionWithinConvertibleTypes(editor, types = []) {
84
+ var _a, _b;
85
+ if (!editor || types.length === 0) return false;
86
+ const { state } = editor;
87
+ const { selection } = state;
88
+ const allowed = new Set(types);
89
+ if (selection instanceof import_state.NodeSelection) {
90
+ const nodeType = (_b = (_a = selection.node) == null ? void 0 : _a.type) == null ? void 0 : _b.name;
91
+ return !!nodeType && allowed.has(nodeType);
92
+ }
93
+ if (selection instanceof import_state.TextSelection || selection instanceof import_state.AllSelection) {
94
+ let valid = true;
95
+ state.doc.nodesBetween(selection.from, selection.to, (node) => {
96
+ if (node.isTextblock && !allowed.has(node.type.name)) {
97
+ valid = false;
98
+ return false;
99
+ }
100
+ return valid;
101
+ });
102
+ return valid;
103
+ }
104
+ return false;
105
+ }
66
106
  // Annotate the CommonJS export names for ESM import in node:
67
107
  0 && (module.exports = {
68
- getSelectedNodesOfType
108
+ getSelectedBlockNodes,
109
+ getSelectedNodesOfType,
110
+ selectionWithinConvertibleTypes
69
111
  });
@@ -0,0 +1,11 @@
1
+ "use client";
2
+ import {
3
+ getSelectedBlockNodes,
4
+ getSelectedNodesOfType,
5
+ selectionWithinConvertibleTypes
6
+ } from "./chunk-ID5T7EEZ.mjs";
7
+ export {
8
+ getSelectedBlockNodes,
9
+ getSelectedNodesOfType,
10
+ selectionWithinConvertibleTypes
11
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kopexa/editor-utils",
3
- "version": "17.0.48",
3
+ "version": "17.1.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.22.9"
33
+ "@kopexa/theme": "17.23.0"
34
34
  },
35
35
  "dependencies": {
36
- "@kopexa/react-utils": "17.0.48",
37
- "@kopexa/shared-utils": "17.0.48"
36
+ "@kopexa/react-utils": "17.0.49",
37
+ "@kopexa/shared-utils": "17.0.49"
38
38
  },
39
39
  "clean-package": "../../../clean-package.config.json",
40
40
  "module": "dist/index.mjs",
@@ -1,46 +0,0 @@
1
- "use client";
2
-
3
- // src/get-selected-nodes-of-type.ts
4
- import { NodeSelection } from "@tiptap/pm/state";
5
- import { CellSelection, cellAround } from "@tiptap/pm/tables";
6
- import { findParentNodeClosestToPos } from "@tiptap/react";
7
- function getSelectedNodesOfType(selection, allowedNodeTypes) {
8
- const results = [];
9
- const allowed = new Set(allowedNodeTypes);
10
- if (selection instanceof CellSelection) {
11
- selection.forEachCell((node, pos) => {
12
- if (allowed.has(node.type.name)) {
13
- results.push({ node, pos });
14
- }
15
- });
16
- return results;
17
- }
18
- if (selection instanceof NodeSelection) {
19
- const { node, from: pos } = selection;
20
- if (node && allowed.has(node.type.name)) {
21
- results.push({ node, pos });
22
- }
23
- return results;
24
- }
25
- const { $anchor } = selection;
26
- const cell = cellAround($anchor);
27
- if (cell) {
28
- const cellNode = selection.$anchor.doc.nodeAt(cell.pos);
29
- if (cellNode && allowed.has(cellNode.type.name)) {
30
- results.push({ node: cellNode, pos: cell.pos });
31
- return results;
32
- }
33
- }
34
- const parentNode = findParentNodeClosestToPos(
35
- $anchor,
36
- (node) => allowed.has(node.type.name)
37
- );
38
- if (parentNode) {
39
- results.push({ node: parentNode.node, pos: parentNode.pos });
40
- }
41
- return results;
42
- }
43
-
44
- export {
45
- getSelectedNodesOfType
46
- };
@@ -1,12 +0,0 @@
1
- import { Selection } from '@tiptap/pm/state';
2
- import { NodeWithPos } from '@tiptap/react';
3
-
4
- /**
5
- * Retrieves all nodes of specified types from the current selection.
6
- * @param selection The current editor selection
7
- * @param allowedNodeTypes An array of node type names to look for (e.g., ["image", "table"])
8
- * @returns An array of objects containing the node and its position
9
- */
10
- declare function getSelectedNodesOfType(selection: Selection, allowedNodeTypes: string[]): NodeWithPos[];
11
-
12
- export { getSelectedNodesOfType };
@@ -1,12 +0,0 @@
1
- import { Selection } from '@tiptap/pm/state';
2
- import { NodeWithPos } from '@tiptap/react';
3
-
4
- /**
5
- * Retrieves all nodes of specified types from the current selection.
6
- * @param selection The current editor selection
7
- * @param allowedNodeTypes An array of node type names to look for (e.g., ["image", "table"])
8
- * @returns An array of objects containing the node and its position
9
- */
10
- declare function getSelectedNodesOfType(selection: Selection, allowedNodeTypes: string[]): NodeWithPos[];
11
-
12
- export { getSelectedNodesOfType };
@@ -1,7 +0,0 @@
1
- "use client";
2
- import {
3
- getSelectedNodesOfType
4
- } from "./chunk-EGCOGZWA.mjs";
5
- export {
6
- getSelectedNodesOfType
7
- };