@use-kona/editor 0.1.28 → 0.1.30
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/core/createEditable.js +4 -1
- package/dist/plugins/CodeBlockPlugin/styles_module.css +1 -0
- package/dist/plugins/CollapsibleBlocksPlugin/CollapsibleBlocksPlugin.js +121 -0
- package/dist/plugins/CollapsibleBlocksPlugin/index.js +2 -0
- package/dist/plugins/CollapsibleBlocksPlugin/styles.module.js +8 -0
- package/dist/plugins/CollapsibleBlocksPlugin/styles_module.css +38 -0
- package/dist/plugins/CommandsPlugin/Menu.js +2 -2
- package/dist/plugins/DnDPlugin/DnDPlugin.js +60 -19
- package/dist/plugins/index.js +2 -1
- package/dist/src/plugins/CollapsibleBlocksPlugin/CollapsibleBlocksPlugin.d.ts +13 -0
- package/dist/src/plugins/CollapsibleBlocksPlugin/index.d.ts +1 -0
- package/dist/src/plugins/DnDPlugin/DnDPlugin.d.ts +2 -1
- package/dist/src/plugins/DnDPlugin/types.d.ts +1 -0
- package/dist/src/plugins/index.d.ts +1 -0
- package/dist/src/types.d.ts +5 -0
- package/dist/types.d.ts +1 -0
- package/package.json +1 -1
- package/src/core/createEditable.tsx +5 -1
- package/src/plugins/CodeBlockPlugin/styles.module.css +1 -0
- package/src/plugins/CollapsibleBlocksPlugin/CollapsibleBlocksPlugin.spec.tsx +216 -0
- package/src/plugins/CollapsibleBlocksPlugin/CollapsibleBlocksPlugin.tsx +191 -0
- package/src/plugins/CollapsibleBlocksPlugin/index.ts +1 -0
- package/src/plugins/CollapsibleBlocksPlugin/styles.module.css +37 -0
- package/src/plugins/CommandsPlugin/Menu.spec.tsx +87 -0
- package/src/plugins/CommandsPlugin/Menu.tsx +2 -2
- package/src/plugins/DnDPlugin/DnDPlugin.spec.ts +346 -0
- package/src/plugins/DnDPlugin/DnDPlugin.tsx +117 -31
- package/src/plugins/DnDPlugin/types.ts +1 -0
- package/src/plugins/index.ts +1 -0
- package/src/types.ts +5 -0
|
@@ -19,6 +19,9 @@ const SUPPORTED_HANDLERS = [
|
|
|
19
19
|
const createEditable = (editor, plugins)=>({ readOnly })=>{
|
|
20
20
|
const [selectedNodes] = useState(()=>atom([]));
|
|
21
21
|
const $selectedNodes = useStore(selectedNodes);
|
|
22
|
+
const renderBlockPlugins = [
|
|
23
|
+
...plugins
|
|
24
|
+
].sort((left, right)=>(left.renderBlockPriority || 0) - (right.renderBlockPriority || 0));
|
|
22
25
|
const renderElement = (props)=>{
|
|
23
26
|
let result = null;
|
|
24
27
|
for (const plugin of plugins)for (const element of plugin.blocks || []){
|
|
@@ -26,7 +29,7 @@ const createEditable = (editor, plugins)=>({ readOnly })=>{
|
|
|
26
29
|
const newElement = element.render(props, editor);
|
|
27
30
|
result = newElement || result;
|
|
28
31
|
}
|
|
29
|
-
for (const plugin of
|
|
32
|
+
for (const plugin of renderBlockPlugins)if (plugin.renderBlock) result = plugin.renderBlock({
|
|
30
33
|
...props,
|
|
31
34
|
children: result || props.children
|
|
32
35
|
});
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Editor, Element, Range, Transforms } from "slate";
|
|
3
|
+
import { ReactEditor, useSlate } from "slate-react";
|
|
4
|
+
import styles_module from "./styles.module.js";
|
|
5
|
+
const sectionTypesByEditor = new WeakMap();
|
|
6
|
+
class CollapsibleBlocksPlugin {
|
|
7
|
+
types;
|
|
8
|
+
renderBlockPriority = -1;
|
|
9
|
+
constructor(types){
|
|
10
|
+
this.types = types;
|
|
11
|
+
}
|
|
12
|
+
init(editor) {
|
|
13
|
+
sectionTypesByEditor.set(editor, this.types);
|
|
14
|
+
return editor;
|
|
15
|
+
}
|
|
16
|
+
renderBlock = (props)=>{
|
|
17
|
+
const editor = useSlate();
|
|
18
|
+
const path = ReactEditor.findPath(editor, props.element);
|
|
19
|
+
if (1 !== path.length) return props.children;
|
|
20
|
+
const isHidden = isHiddenByCollapsedBoundary(editor, path, this.types);
|
|
21
|
+
if (isHidden) return /*#__PURE__*/ jsx("div", {
|
|
22
|
+
className: styles_module.hidden,
|
|
23
|
+
"data-collapsible-block-hidden": true,
|
|
24
|
+
hidden: true,
|
|
25
|
+
children: props.children
|
|
26
|
+
});
|
|
27
|
+
if (this.types.includes(props.element.type)) return /*#__PURE__*/ jsx(CollapsibleBoundary, {
|
|
28
|
+
editor: editor,
|
|
29
|
+
element: props.element,
|
|
30
|
+
path: path,
|
|
31
|
+
types: this.types,
|
|
32
|
+
children: props.children
|
|
33
|
+
});
|
|
34
|
+
return props.children;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const CollapsibleBoundary = ({ children, editor, element, path, types })=>{
|
|
38
|
+
const isCollapsed = true === element.collapsed;
|
|
39
|
+
const toggle = ()=>{
|
|
40
|
+
const willCollapse = !isCollapsed;
|
|
41
|
+
Transforms.setNodes(editor, {
|
|
42
|
+
collapsed: willCollapse
|
|
43
|
+
}, {
|
|
44
|
+
at: path
|
|
45
|
+
});
|
|
46
|
+
if (willCollapse && isSelectionInsideSection(editor, path, types)) Transforms.select(editor, Editor.start(editor, path));
|
|
47
|
+
};
|
|
48
|
+
return /*#__PURE__*/ jsxs("div", {
|
|
49
|
+
className: styles_module.boundary,
|
|
50
|
+
children: [
|
|
51
|
+
/*#__PURE__*/ jsx("button", {
|
|
52
|
+
"aria-expanded": !isCollapsed,
|
|
53
|
+
"aria-label": isCollapsed ? 'Expand section' : 'Collapse section',
|
|
54
|
+
className: isCollapsed ? styles_module.chevron : `${styles_module.chevron} ${styles_module.expanded}`,
|
|
55
|
+
contentEditable: false,
|
|
56
|
+
onClick: toggle,
|
|
57
|
+
onMouseDown: (event)=>event.preventDefault(),
|
|
58
|
+
type: "button",
|
|
59
|
+
children: /*#__PURE__*/ jsxs("svg", {
|
|
60
|
+
"aria-hidden": "true",
|
|
61
|
+
fill: "none",
|
|
62
|
+
height: "16",
|
|
63
|
+
stroke: "currentColor",
|
|
64
|
+
strokeLinecap: "round",
|
|
65
|
+
strokeLinejoin: "round",
|
|
66
|
+
strokeWidth: "1.5",
|
|
67
|
+
viewBox: "0 0 24 24",
|
|
68
|
+
width: "16",
|
|
69
|
+
children: [
|
|
70
|
+
/*#__PURE__*/ jsx("path", {
|
|
71
|
+
d: "M0 0h24v24H0z",
|
|
72
|
+
fill: "none",
|
|
73
|
+
stroke: "none"
|
|
74
|
+
}),
|
|
75
|
+
/*#__PURE__*/ jsx("path", {
|
|
76
|
+
d: "M9 6l6 6l-6 6"
|
|
77
|
+
})
|
|
78
|
+
]
|
|
79
|
+
})
|
|
80
|
+
}),
|
|
81
|
+
children
|
|
82
|
+
]
|
|
83
|
+
});
|
|
84
|
+
};
|
|
85
|
+
const getCollapsibleSectionPaths = (editor, path)=>{
|
|
86
|
+
const types = sectionTypesByEditor.get(editor);
|
|
87
|
+
if (!types || 1 !== path.length) return null;
|
|
88
|
+
const boundary = editor.children[path[0]];
|
|
89
|
+
if (!boundary || !types.includes(boundary.type)) return null;
|
|
90
|
+
const end = getSectionEnd(editor, path[0], types);
|
|
91
|
+
return Array.from({
|
|
92
|
+
length: end - path[0]
|
|
93
|
+
}, (_, index)=>[
|
|
94
|
+
path[0] + index
|
|
95
|
+
]);
|
|
96
|
+
};
|
|
97
|
+
const isHiddenByCollapsedBoundary = (editor, path, types)=>{
|
|
98
|
+
for(let index = 0; index < path[0]; index++){
|
|
99
|
+
const node = editor.children[index];
|
|
100
|
+
if (Element.isElement(node) && true === node.collapsed && types.includes(node.type) && path[0] < getSectionEnd(editor, index, types)) return true;
|
|
101
|
+
}
|
|
102
|
+
return false;
|
|
103
|
+
};
|
|
104
|
+
const isSelectionInsideSection = (editor, boundaryPath, types)=>{
|
|
105
|
+
const { selection } = editor;
|
|
106
|
+
if (!selection || !Range.isCollapsed(selection)) return false;
|
|
107
|
+
const selectionIndex = selection.focus.path[0];
|
|
108
|
+
if (selectionIndex <= boundaryPath[0]) return false;
|
|
109
|
+
return selectionIndex < getSectionEnd(editor, boundaryPath[0], types);
|
|
110
|
+
};
|
|
111
|
+
const getSectionEnd = (editor, boundaryIndex, types)=>{
|
|
112
|
+
const boundary = editor.children[boundaryIndex];
|
|
113
|
+
const boundaryLevel = types.indexOf(boundary.type);
|
|
114
|
+
for(let index = boundaryIndex + 1; index < editor.children.length; index++){
|
|
115
|
+
const node = editor.children[index];
|
|
116
|
+
const nodeLevel = Element.isElement(node) ? types.indexOf(node.type) : -1;
|
|
117
|
+
if (-1 !== nodeLevel && nodeLevel <= boundaryLevel) return index;
|
|
118
|
+
}
|
|
119
|
+
return editor.children.length;
|
|
120
|
+
};
|
|
121
|
+
export { CollapsibleBlocksPlugin, getCollapsibleSectionPaths };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
.boundary-gLj40W {
|
|
2
|
+
position: relative;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
.chevron-up0Fid {
|
|
6
|
+
appearance: none;
|
|
7
|
+
color: inherit;
|
|
8
|
+
cursor: pointer;
|
|
9
|
+
inset-inline-start: -20px;
|
|
10
|
+
width: 16px;
|
|
11
|
+
height: 16px;
|
|
12
|
+
font: inherit;
|
|
13
|
+
background: none;
|
|
14
|
+
border: 0;
|
|
15
|
+
justify-content: center;
|
|
16
|
+
align-items: center;
|
|
17
|
+
margin: 0;
|
|
18
|
+
padding: 0;
|
|
19
|
+
line-height: 1;
|
|
20
|
+
transition: transform .15s;
|
|
21
|
+
display: flex;
|
|
22
|
+
position: absolute;
|
|
23
|
+
top: 50%;
|
|
24
|
+
transform: translateY(-50%);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.expanded-HCZXmg {
|
|
28
|
+
transform: translateY(-50%)rotate(90deg);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.chevron-up0Fid svg {
|
|
32
|
+
display: block;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.hidden-icZZ78 {
|
|
36
|
+
display: none;
|
|
37
|
+
}
|
|
38
|
+
|
|
@@ -196,9 +196,9 @@ const Menu = (props)=>{
|
|
|
196
196
|
break;
|
|
197
197
|
}
|
|
198
198
|
};
|
|
199
|
-
document.addEventListener('keydown', handleKeyDown);
|
|
199
|
+
document.addEventListener('keydown', handleKeyDown, true);
|
|
200
200
|
return ()=>{
|
|
201
|
-
document.removeEventListener('keydown', handleKeyDown);
|
|
201
|
+
document.removeEventListener('keydown', handleKeyDown, true);
|
|
202
202
|
};
|
|
203
203
|
}, [
|
|
204
204
|
actions,
|
|
@@ -6,6 +6,7 @@ import { NativeTypes } from "react-dnd-html5-backend";
|
|
|
6
6
|
import { Editor, Element, Path, Transforms } from "slate";
|
|
7
7
|
import { ReactEditor, useReadOnly, useSlate } from "slate-react";
|
|
8
8
|
import { useEditorContext } from "../../provider.js";
|
|
9
|
+
import { getCollapsibleSectionPaths } from "../CollapsibleBlocksPlugin/CollapsibleBlocksPlugin.js";
|
|
9
10
|
import { getNodesByNodeIds } from "./utils.js";
|
|
10
11
|
class DnDPlugin {
|
|
11
12
|
options;
|
|
@@ -37,7 +38,9 @@ class DnDPlugin {
|
|
|
37
38
|
type: customType?.type || DnDPlugin.DND_BLOCK_ELEMENT,
|
|
38
39
|
item: ()=>{
|
|
39
40
|
const selected = $selectedNodes;
|
|
40
|
-
const
|
|
41
|
+
const path = ReactEditor.findPath(editor, props.element);
|
|
42
|
+
const sectionPaths = getCollapsibleSectionPaths(editor, path);
|
|
43
|
+
const nodes = sectionPaths ? getNodesAtPaths(editor, sectionPaths) : selected.length > 0 && selected.find((node)=>node.nodeId === currentElement.nodeId) ? getNodesByNodeIds(editor, selected.map((node)=>node.nodeId)) : [
|
|
41
44
|
structuredClone(props.element)
|
|
42
45
|
];
|
|
43
46
|
const item = this.options.customTypes?.[currentElement.type]?.getData?.(currentElement);
|
|
@@ -52,7 +55,9 @@ class DnDPlugin {
|
|
|
52
55
|
items,
|
|
53
56
|
source: {
|
|
54
57
|
editor,
|
|
55
|
-
documentId: options.documentId
|
|
58
|
+
documentId: options.documentId,
|
|
59
|
+
path,
|
|
60
|
+
sectionPaths: sectionPaths || void 0
|
|
56
61
|
}
|
|
57
62
|
};
|
|
58
63
|
return dragItem;
|
|
@@ -77,14 +82,8 @@ class DnDPlugin {
|
|
|
77
82
|
};
|
|
78
83
|
},
|
|
79
84
|
hover (_, monitor) {
|
|
80
|
-
const
|
|
81
|
-
if (
|
|
82
|
-
const hoverBoundingRect = element.getBoundingClientRect();
|
|
83
|
-
const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
|
|
84
|
-
const clientOffset = monitor.getClientOffset();
|
|
85
|
-
if (!clientOffset) return;
|
|
86
|
-
const hoverClientY = clientOffset.y - hoverBoundingRect.top;
|
|
87
|
-
hoverClientY < hoverMiddleY ? setDropPosition('top') : setDropPosition('bottom');
|
|
85
|
+
const position = getDropPosition(dropTargetRef.current, monitor);
|
|
86
|
+
if (position) setDropPosition(position);
|
|
88
87
|
},
|
|
89
88
|
drop: (data, monitor)=>{
|
|
90
89
|
const itemType = monitor.getItemType();
|
|
@@ -93,7 +92,8 @@ class DnDPlugin {
|
|
|
93
92
|
const isSameEditor = 'inner' === data.kind && data.source?.editor === editor;
|
|
94
93
|
const sourceTo = ReactEditor.findPath(editor, props.element);
|
|
95
94
|
if (!sourceTo) return;
|
|
96
|
-
const
|
|
95
|
+
const position = getDropPosition(dropTargetRef.current, monitor) || dropPosition || 'bottom';
|
|
96
|
+
const insertAt = getDropPath(editor, sourceTo, position);
|
|
97
97
|
if (!insertAt) return;
|
|
98
98
|
const customDropHandler = itemType && options.customDropHandlers?.[itemType];
|
|
99
99
|
if (customDropHandler && 'outer' === data.kind) return void customDropHandler.onDrop({
|
|
@@ -109,18 +109,18 @@ class DnDPlugin {
|
|
|
109
109
|
{
|
|
110
110
|
const dragItem = data;
|
|
111
111
|
if ('outer' === dragItem.kind) return;
|
|
112
|
-
if (!
|
|
113
|
-
const nodeIds = dragItem.nodes.map((node)=>node.nodeId);
|
|
112
|
+
if (!dragItem.nodes.length) return;
|
|
113
|
+
const nodeIds = dragItem.nodes.map((node)=>node.nodeId).filter((nodeId)=>'string' == typeof nodeId);
|
|
114
114
|
if (isSameDocument || isSameEditor) if (isCopying.current) {
|
|
115
115
|
if (!generateId) return;
|
|
116
116
|
const clonedNodes = cloneWithNewIds(dragItem.nodes, generateId);
|
|
117
117
|
insertNodes(editor, insertAt, clonedNodes);
|
|
118
|
-
} else moveNode(editor, sourceTo, nodeIds,
|
|
118
|
+
} else moveNode(editor, sourceTo, nodeIds, position, dragItem.source.path, dragItem.source.sectionPaths);
|
|
119
119
|
else {
|
|
120
120
|
if (!generateId) return;
|
|
121
121
|
const clonedNodes = cloneWithNewIds(dragItem.nodes, generateId);
|
|
122
122
|
insertNodes(editor, insertAt, clonedNodes);
|
|
123
|
-
if (!isCopying.current && sourceEditor) removeNodes(sourceEditor, nodeIds);
|
|
123
|
+
if (!isCopying.current && sourceEditor) removeNodes(sourceEditor, nodeIds, dragItem.source.sectionPaths);
|
|
124
124
|
}
|
|
125
125
|
selectedNodes.set([]);
|
|
126
126
|
break;
|
|
@@ -174,11 +174,33 @@ const getDropPath = (editor, targetNodePath, position)=>{
|
|
|
174
174
|
return Path.next(target[1]);
|
|
175
175
|
}
|
|
176
176
|
};
|
|
177
|
-
const
|
|
177
|
+
const getDropPosition = (element, monitor)=>{
|
|
178
|
+
if (!element) return null;
|
|
179
|
+
const clientOffset = monitor.getClientOffset();
|
|
180
|
+
if (!clientOffset) return null;
|
|
181
|
+
const rect = element.getBoundingClientRect();
|
|
182
|
+
return clientOffset.y - rect.top < (rect.bottom - rect.top) / 2 ? 'top' : 'bottom';
|
|
183
|
+
};
|
|
184
|
+
const moveNode = (editor, targetNodePath, nodeIds, position, sourcePath, sectionPaths)=>{
|
|
178
185
|
const dropPath = getDropPath(editor, targetNodePath, position);
|
|
179
186
|
if (!dropPath) return;
|
|
180
|
-
if (!
|
|
187
|
+
if (!isValidInsertPath(editor, dropPath)) return;
|
|
188
|
+
if (sectionPaths?.some((path)=>Path.equals(path, targetNodePath))) return;
|
|
181
189
|
Editor.withoutNormalizing(editor, ()=>{
|
|
190
|
+
if (sectionPaths?.length) {
|
|
191
|
+
const sectionNodes = new Set(sectionPaths.filter((path)=>Editor.hasPath(editor, path)).map((path)=>Editor.node(editor, path)[0]));
|
|
192
|
+
Transforms.moveNodes(editor, {
|
|
193
|
+
at: [],
|
|
194
|
+
match: (node)=>sectionNodes.has(node),
|
|
195
|
+
to: dropPath,
|
|
196
|
+
mode: 'highest'
|
|
197
|
+
});
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
if (0 === nodeIds.length && sourcePath && Editor.hasPath(editor, sourcePath)) return void Transforms.moveNodes(editor, {
|
|
201
|
+
at: sourcePath,
|
|
202
|
+
to: dropPath
|
|
203
|
+
});
|
|
182
204
|
Transforms.moveNodes(editor, {
|
|
183
205
|
at: [],
|
|
184
206
|
match: (n)=>{
|
|
@@ -194,6 +216,13 @@ const moveNode = (editor, targetNodePath, nodeIds, position)=>{
|
|
|
194
216
|
});
|
|
195
217
|
Editor.normalize(editor);
|
|
196
218
|
};
|
|
219
|
+
const isValidInsertPath = (editor, path)=>{
|
|
220
|
+
const parentPath = Path.parent(path);
|
|
221
|
+
const index = path[path.length - 1];
|
|
222
|
+
if (void 0 === index || !Editor.hasPath(editor, parentPath)) return false;
|
|
223
|
+
const [parent] = Editor.node(editor, parentPath);
|
|
224
|
+
return 'children' in parent && index <= parent.children.length;
|
|
225
|
+
};
|
|
197
226
|
const insertNodes = (editor, path, nodes)=>{
|
|
198
227
|
Editor.withoutNormalizing(editor, ()=>{
|
|
199
228
|
Transforms.insertNodes(editor, nodes, {
|
|
@@ -201,8 +230,20 @@ const insertNodes = (editor, path, nodes)=>{
|
|
|
201
230
|
});
|
|
202
231
|
});
|
|
203
232
|
};
|
|
204
|
-
const
|
|
233
|
+
const getNodesAtPaths = (editor, paths)=>paths.filter((path)=>Editor.hasPath(editor, path)).map((path)=>structuredClone(Editor.node(editor, path)[0]));
|
|
234
|
+
const removeNodes = (editor, nodeIds, sectionPaths)=>{
|
|
205
235
|
try {
|
|
236
|
+
if (sectionPaths?.length) {
|
|
237
|
+
const paths = sectionPaths.filter((path)=>Editor.hasPath(editor, path)).sort((left, right)=>Path.compare(right, left));
|
|
238
|
+
Editor.withoutNormalizing(editor, ()=>{
|
|
239
|
+
paths.forEach((path)=>{
|
|
240
|
+
Transforms.removeNodes(editor, {
|
|
241
|
+
at: path
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
});
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
206
247
|
Transforms.removeNodes(editor, {
|
|
207
248
|
at: [],
|
|
208
249
|
match: (n)=>{
|
|
@@ -228,4 +269,4 @@ const cloneWithNewIds = (nodes, generateId)=>{
|
|
|
228
269
|
copy.forEach(assignId);
|
|
229
270
|
return copy;
|
|
230
271
|
};
|
|
231
|
-
export { DnDPlugin };
|
|
272
|
+
export { DnDPlugin, moveNode };
|
package/dist/plugins/index.js
CHANGED
|
@@ -2,6 +2,7 @@ import { AttachmentsPlugin } from "./AttachmentsPlugin/index.js";
|
|
|
2
2
|
import { BasicFormattingPlugin } from "./BasicFormattingPlugin/index.js";
|
|
3
3
|
import { BreaksPlugin } from "./BreaksPlugin/index.js";
|
|
4
4
|
import { CodeBlockPlugin } from "./CodeBlockPlugin/index.js";
|
|
5
|
+
import { CollapsibleBlocksPlugin } from "./CollapsibleBlocksPlugin/index.js";
|
|
5
6
|
import { CommandsPlugin } from "./CommandsPlugin/index.js";
|
|
6
7
|
import { DnDPlugin } from "./DnDPlugin/index.js";
|
|
7
8
|
import { EmojiPlugin } from "./EmojiPlugin/index.js";
|
|
@@ -15,4 +16,4 @@ import { NodeIdPlugin } from "./NodeIdPlugin/index.js";
|
|
|
15
16
|
import { PlaceholderPlugin } from "./PlaceholderPlugin/index.js";
|
|
16
17
|
import { ShortcutsPlugin } from "./ShortcutsPlugin/index.js";
|
|
17
18
|
import { TableOfContentsPlugin } from "./TableOfContentsPlugin/index.js";
|
|
18
|
-
export { AttachmentsPlugin, BasicFormattingPlugin, BreaksPlugin, CodeBlockPlugin, CommandsPlugin, DnDPlugin, EmojiPlugin, FloatingMenuPlugin, HeadingsPlugin, HighlightsPlugin, LinksPlugin, ListsPlugin, MenuPlugin, NodeIdPlugin, PlaceholderPlugin, ShortcutsPlugin, TableOfContentsPlugin, isSafeLinkUrl };
|
|
19
|
+
export { AttachmentsPlugin, BasicFormattingPlugin, BreaksPlugin, CodeBlockPlugin, CollapsibleBlocksPlugin, CommandsPlugin, DnDPlugin, EmojiPlugin, FloatingMenuPlugin, HeadingsPlugin, HighlightsPlugin, LinksPlugin, ListsPlugin, MenuPlugin, NodeIdPlugin, PlaceholderPlugin, ShortcutsPlugin, TableOfContentsPlugin, isSafeLinkUrl };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Editor, type Path } from 'slate';
|
|
2
|
+
import { ReactEditor, type RenderElementProps } from 'slate-react';
|
|
3
|
+
import type { IPlugin } from '../../types';
|
|
4
|
+
export declare class CollapsibleBlocksPlugin implements IPlugin {
|
|
5
|
+
private types;
|
|
6
|
+
renderBlockPriority: number;
|
|
7
|
+
constructor(types: string[]);
|
|
8
|
+
init(editor: Editor): import("slate").BaseEditor & ReactEditor & {
|
|
9
|
+
getCommands: <T extends IPlugin>(plugin: new () => T) => T["commands"];
|
|
10
|
+
};
|
|
11
|
+
renderBlock: (props: RenderElementProps) => any;
|
|
12
|
+
}
|
|
13
|
+
export declare const getCollapsibleSectionPaths: (editor: Editor, path: Path) => number[][] | null;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { CollapsibleBlocksPlugin } from './CollapsibleBlocksPlugin';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Editor } from 'slate';
|
|
1
|
+
import { Editor, Path } from 'slate';
|
|
2
2
|
import { ReactEditor, type RenderElementProps } from 'slate-react';
|
|
3
3
|
import type { IPlugin } from '../../types';
|
|
4
4
|
import type { Options } from './types';
|
|
@@ -14,3 +14,4 @@ export declare class DnDPlugin implements IPlugin {
|
|
|
14
14
|
};
|
|
15
15
|
renderBlock: (props: RenderElementProps) => any;
|
|
16
16
|
}
|
|
17
|
+
export declare const moveNode: (editor: Editor, targetNodePath: Path, nodeIds: string[], position: "top" | "bottom", sourcePath?: Path, sectionPaths?: Path[]) => void;
|
|
@@ -2,6 +2,7 @@ export { AttachmentsPlugin } from './AttachmentsPlugin';
|
|
|
2
2
|
export { BasicFormattingPlugin } from './BasicFormattingPlugin';
|
|
3
3
|
export { BreaksPlugin } from './BreaksPlugin';
|
|
4
4
|
export { CodeBlockPlugin, type CodeElement } from './CodeBlockPlugin';
|
|
5
|
+
export { CollapsibleBlocksPlugin } from './CollapsibleBlocksPlugin';
|
|
5
6
|
export { type Command, type CommandPathEntry, CommandsPlugin, type GetCommandsContext, } from './CommandsPlugin';
|
|
6
7
|
export { DnDPlugin } from './DnDPlugin';
|
|
7
8
|
export { EmojiPlugin } from './EmojiPlugin';
|
package/dist/src/types.d.ts
CHANGED
|
@@ -8,6 +8,11 @@ export interface IPlugin<TEditor extends Editor = Editor, TBlock extends CustomE
|
|
|
8
8
|
blocks?: Block<TEditor, TBlock>[];
|
|
9
9
|
leafs?: Leaf<TEditor, TLeaf>[];
|
|
10
10
|
hotkeys?: Hotkey[];
|
|
11
|
+
/**
|
|
12
|
+
* Render block wrappers from lower to higher priority. Plugins with the same
|
|
13
|
+
* priority retain the order supplied to KonaEditor.
|
|
14
|
+
*/
|
|
15
|
+
renderBlockPriority?: number;
|
|
11
16
|
renderBlock?: (props: RenderElementProps) => ReactElement | null;
|
|
12
17
|
renderLeaf?: (props: RenderLeafProps) => ReactElement | null;
|
|
13
18
|
handlers?: {
|
package/dist/types.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -47,6 +47,10 @@ export const createEditable =
|
|
|
47
47
|
const [selectedNodes] = useState(() => atom<CustomElement[]>([]));
|
|
48
48
|
|
|
49
49
|
const $selectedNodes = useStore(selectedNodes);
|
|
50
|
+
const renderBlockPlugins = [...plugins].sort(
|
|
51
|
+
(left, right) =>
|
|
52
|
+
(left.renderBlockPriority || 0) - (right.renderBlockPriority || 0),
|
|
53
|
+
);
|
|
50
54
|
|
|
51
55
|
const renderElement = (props: RenderElementProps): ReactElement => {
|
|
52
56
|
let result: ReactElement | null = null;
|
|
@@ -60,7 +64,7 @@ export const createEditable =
|
|
|
60
64
|
}
|
|
61
65
|
}
|
|
62
66
|
|
|
63
|
-
for (const plugin of
|
|
67
|
+
for (const plugin of renderBlockPlugins) {
|
|
64
68
|
if (plugin.renderBlock) {
|
|
65
69
|
result = plugin.renderBlock({
|
|
66
70
|
...props,
|