@use-kona/editor 0.1.24 → 0.1.25

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.
Files changed (36) hide show
  1. package/dist/core/createEditable.js +146 -15
  2. package/dist/core/createEditor.js +1 -1
  3. package/dist/core/styles.module.js +3 -1
  4. package/dist/core/styles_module.css +13 -0
  5. package/dist/elements/Block.js +25 -0
  6. package/dist/index.js +2 -1
  7. package/dist/plugins/CodeBlockPlugin/CodeBlockPlugin.js +1 -1
  8. package/dist/plugins/DnDPlugin/DnDPlugin.js +93 -45
  9. package/dist/plugins/DnDPlugin/types.js +2 -0
  10. package/dist/plugins/HeadingsPlugin/HeadingsPlugin.js +1 -1
  11. package/dist/plugins/ListsPlugin/ListsPlugin.js +1 -1
  12. package/dist/plugins/NodeIdPlugin/NodeIdPlugin.js +6 -4
  13. package/dist/provider.js +15 -0
  14. package/dist/src/core/createEditable.d.ts +1 -1
  15. package/dist/src/elements/Block.d.ts +2 -0
  16. package/dist/src/index.d.ts +1 -0
  17. package/dist/src/plugins/DnDPlugin/DnDPlugin.d.ts +0 -7
  18. package/dist/src/plugins/DnDPlugin/types.d.ts +29 -15
  19. package/dist/src/plugins/NodeIdPlugin/NodeIdPlugin.d.ts +1 -0
  20. package/dist/src/provider.d.ts +8 -0
  21. package/dist/src/types.d.ts +4 -0
  22. package/package.json +9 -8
  23. package/src/core/createEditable.tsx +170 -18
  24. package/src/core/createEditor.ts +1 -1
  25. package/src/core/styles.module.css +12 -0
  26. package/src/editor.tsx +4 -3
  27. package/src/elements/Block.tsx +31 -0
  28. package/src/index.ts +1 -0
  29. package/src/plugins/CodeBlockPlugin/CodeBlockPlugin.tsx +1 -3
  30. package/src/plugins/DnDPlugin/DnDPlugin.tsx +147 -62
  31. package/src/plugins/DnDPlugin/types.ts +35 -20
  32. package/src/plugins/HeadingsPlugin/HeadingsPlugin.tsx +1 -2
  33. package/src/plugins/ListsPlugin/ListsPlugin.tsx +5 -5
  34. package/src/plugins/NodeIdPlugin/NodeIdPlugin.ts +9 -7
  35. package/src/provider.tsx +28 -0
  36. package/src/types.ts +5 -0
@@ -1,9 +1,13 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useStore } from "@nanostores/react";
2
3
  import is_hotkey from "is-hotkey";
3
- import react, { isValidElement, useCallback } from "react";
4
- import { Transforms } from "slate";
5
- import { Editable, useReadOnly } from "slate-react";
4
+ import { atom } from "nanostores";
5
+ import react, { isValidElement, useCallback, useState } from "react";
6
+ import { Editor, Element, Path, Transforms } from "slate";
7
+ import { Editable, ReactEditor, useReadOnly } from "slate-react";
6
8
  import { BaseElement } from "../elements/BaseElement.js";
9
+ import { Block } from "../elements/Block.js";
10
+ import { EditorProvider } from "../provider.js";
7
11
  import { deserialize } from "./deserialize.js";
8
12
  import styles_module from "./styles.module.js";
9
13
  const SUPPORTED_HANDLERS = [
@@ -13,6 +17,8 @@ const SUPPORTED_HANDLERS = [
13
17
  'onPaste'
14
18
  ];
15
19
  const createEditable = (editor, plugins)=>({ readOnly })=>{
20
+ const [selectedNodes] = useState(()=>atom([]));
21
+ const $selectedNodes = useStore(selectedNodes);
16
22
  const renderElement = (props)=>{
17
23
  let result = null;
18
24
  for (const plugin of plugins)for (const element of plugin.blocks || []){
@@ -24,13 +30,20 @@ const createEditable = (editor, plugins)=>({ readOnly })=>{
24
30
  ...props,
25
31
  children: result || props.children
26
32
  });
27
- return result || /*#__PURE__*/ jsx(BaseElement, {
33
+ if (Editor.isInline(editor, props.element)) return result || /*#__PURE__*/ jsx(BaseElement, {
28
34
  ...props
29
35
  });
36
+ return /*#__PURE__*/ jsx(Block, {
37
+ element: props.element,
38
+ attributes: props.attributes,
39
+ children: result || /*#__PURE__*/ jsx(BaseElement, {
40
+ ...props
41
+ })
42
+ });
30
43
  };
31
44
  const renderLeaf = (props)=>{
32
45
  let result;
33
- for (const plugin of plugins)plugin.leafs?.map((element)=>{
46
+ for (const plugin of plugins)plugin.leafs?.forEach((element)=>{
34
47
  const newElement = element.render({
35
48
  ...props,
36
49
  children: result || props.children
@@ -41,6 +54,121 @@ const createEditable = (editor, plugins)=>({ readOnly })=>{
41
54
  };
42
55
  const handleHotkey = (event)=>{
43
56
  if ('Tab' === event.key) event.preventDefault();
57
+ if ('Escape' === event.key) {
58
+ const currentBlock = Editor.above(editor, {
59
+ at: editor.selection?.focus,
60
+ match: (n)=>Element.isElement(n) && Editor.isBlock(editor, n)
61
+ });
62
+ if (!currentBlock) return;
63
+ if (0 === $selectedNodes.length) selectedNodes.set([
64
+ currentBlock[0]
65
+ ]);
66
+ else {
67
+ selectedNodes.set([]);
68
+ ReactEditor.blur(editor);
69
+ }
70
+ } else if ('ArrowDown' === event.key) {
71
+ const currentBlock = Editor.above(editor, {
72
+ at: editor.selection?.focus,
73
+ match: (n)=>Element.isElement(n)
74
+ });
75
+ if (!currentBlock) return;
76
+ const nextBlock = Editor.next(editor, {
77
+ at: currentBlock[1],
78
+ match: (n)=>Element.isElement(n),
79
+ voids: true
80
+ });
81
+ if (nextBlock) {
82
+ if (Editor.isVoid(editor, nextBlock[0])) {
83
+ event.preventDefault();
84
+ selectedNodes.set([
85
+ nextBlock[0]
86
+ ]);
87
+ } else selectedNodes.set([]);
88
+ if (Editor.isVoid(editor, currentBlock[0]) || Editor.isVoid(editor, nextBlock[0])) {
89
+ event.preventDefault();
90
+ Transforms.select(editor, nextBlock[1]);
91
+ Transforms.collapse(editor, {
92
+ edge: 'start'
93
+ });
94
+ }
95
+ }
96
+ } else if ('ArrowUp' === event.key) {
97
+ const currentBlock = Editor.above(editor, {
98
+ at: editor.selection?.focus,
99
+ match: (n)=>Element.isElement(n)
100
+ });
101
+ if (!currentBlock) return;
102
+ const prevBlock = Editor.previous(editor, {
103
+ at: currentBlock[1],
104
+ match: (n)=>Element.isElement(n),
105
+ voids: true
106
+ });
107
+ if (prevBlock) {
108
+ if (Editor.isVoid(editor, prevBlock[0])) {
109
+ event.preventDefault();
110
+ selectedNodes.set([
111
+ prevBlock[0]
112
+ ]);
113
+ } else selectedNodes.set([]);
114
+ if (Editor.isVoid(editor, currentBlock[0]) || Editor.isVoid(editor, prevBlock[0])) {
115
+ event.preventDefault();
116
+ Transforms.select(editor, prevBlock[1]);
117
+ Transforms.collapse(editor, {
118
+ edge: 'end'
119
+ });
120
+ }
121
+ }
122
+ } else if ('Backspace' === event.key) {
123
+ const currentBlock = Editor.above(editor, {
124
+ at: editor.selection?.focus,
125
+ match: (n)=>Element.isElement(n) && Editor.isBlock(editor, n)
126
+ });
127
+ if (!currentBlock) return;
128
+ if (editor.selection?.focus.offset !== 0) return;
129
+ const prevBlock = Editor.previous(editor, {
130
+ at: currentBlock[1],
131
+ match: (n)=>Element.isElement(n),
132
+ voids: true
133
+ });
134
+ if (prevBlock && Editor.isVoid(editor, prevBlock[0])) {
135
+ event.preventDefault();
136
+ Transforms.removeNodes(editor, {
137
+ at: currentBlock[1]
138
+ });
139
+ Transforms.select(editor, prevBlock[1]);
140
+ selectedNodes.set([
141
+ prevBlock[0]
142
+ ]);
143
+ Transforms.collapse(editor, {
144
+ edge: 'start'
145
+ });
146
+ }
147
+ } else if ('Enter' === event.key) {
148
+ const currentBlock = Editor.above(editor, {
149
+ at: editor.selection?.focus,
150
+ match: (n)=>Element.isElement(n)
151
+ });
152
+ if (!currentBlock) return;
153
+ if (Editor.isVoid(editor, currentBlock[0])) {
154
+ event.preventDefault();
155
+ Transforms.insertNodes(editor, {
156
+ type: 'paragraph',
157
+ children: [
158
+ {
159
+ text: ''
160
+ }
161
+ ]
162
+ }, {
163
+ at: Path.next(currentBlock[1])
164
+ });
165
+ selectedNodes.set([]);
166
+ Transforms.select(editor, Path.next(currentBlock[1]));
167
+ Transforms.collapse(editor, {
168
+ edge: 'start'
169
+ });
170
+ }
171
+ }
44
172
  for (const plugin of plugins)if (plugin.hotkeys) {
45
173
  for (const hotkey of plugin.hotkeys)if (is_hotkey(hotkey[0], event) && hotkey[1]) {
46
174
  event.preventDefault();
@@ -95,7 +223,7 @@ const createEditable = (editor, plugins)=>({ readOnly })=>{
95
223
  },
96
224
  children: [
97
225
  ui.map((p, index)=>/*#__PURE__*/ jsx(react.Fragment, {
98
- children: p.ui({
226
+ children: p.ui?.({
99
227
  readOnly,
100
228
  children,
101
229
  editor
@@ -111,15 +239,18 @@ const createEditable = (editor, plugins)=>({ readOnly })=>{
111
239
  editor,
112
240
  plugins.filter
113
241
  ]);
114
- return /*#__PURE__*/ jsx("div", {
115
- className: styles_module.root,
116
- children: /*#__PURE__*/ jsx(Ui, {
117
- children: /*#__PURE__*/ jsx(Editable, {
118
- decorate: decorate,
119
- renderElement: renderElement,
120
- renderLeaf: renderLeaf,
121
- readOnly: readOnly,
122
- ...handlers
242
+ return /*#__PURE__*/ jsx(EditorProvider, {
243
+ selectedNodes: selectedNodes,
244
+ children: /*#__PURE__*/ jsx("div", {
245
+ className: styles_module.root,
246
+ children: /*#__PURE__*/ jsx(Ui, {
247
+ children: /*#__PURE__*/ jsx(Editable, {
248
+ decorate: decorate,
249
+ renderElement: renderElement,
250
+ renderLeaf: renderLeaf,
251
+ readOnly: readOnly,
252
+ ...handlers
253
+ })
123
254
  })
124
255
  })
125
256
  });
@@ -136,7 +136,7 @@ const createEditor_createEditor = (plugins)=>()=>{
136
136
  const hasOnBeforeDelete = match?.onBeforeDelete;
137
137
  if (!hasOnBeforeDelete) return void deleteFragment(options);
138
138
  {
139
- const result = await match.onBeforeDelete([
139
+ const result = await match.onBeforeDelete?.([
140
140
  node
141
141
  ]);
142
142
  if (!result) return;
@@ -2,6 +2,8 @@ import "./styles_module.css";
2
2
  const styles_module = {
3
3
  root: "root-e1gdll",
4
4
  ui: "ui-I68yAA",
5
- editor: "editor-K2itFp"
5
+ editor: "editor-K2itFp",
6
+ block: "block-sBBbL1",
7
+ selected: "selected-dNsAIz"
6
8
  };
7
9
  export { styles_module as default };
@@ -33,3 +33,16 @@
33
33
  }
34
34
  }
35
35
 
36
+ .block-sBBbL1 {
37
+ transition: background-color .2s ease-in-out;
38
+
39
+ &.selected-dNsAIz {
40
+ background-color: var(--kona-editor-selected-color);
41
+
42
+ & > * {
43
+ transition: transform .2s ease-in-out;
44
+ transform: scale(.98);
45
+ }
46
+ }
47
+ }
48
+
@@ -0,0 +1,25 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { useStore } from "@nanostores/react";
3
+ import { Editor } from "slate";
4
+ import { useSlateStatic } from "slate-react";
5
+ import styles_module from "../core/styles.module.js";
6
+ import { useEditorContext } from "../provider.js";
7
+ const Block = (props)=>{
8
+ const editor = useSlateStatic();
9
+ const { selectedNodes } = useEditorContext();
10
+ const $selectedNodes = useStore(selectedNodes);
11
+ const isSelected = $selectedNodes.some((node)=>node === props.element);
12
+ const classes = isSelected ? `${styles_module.block} ${styles_module.selected}` : styles_module.block;
13
+ const handleClick = ()=>{
14
+ if (Editor.isVoid(editor, props.element)) selectedNodes.set([
15
+ props.element
16
+ ]);
17
+ else selectedNodes.set([]);
18
+ };
19
+ return /*#__PURE__*/ jsx("div", {
20
+ className: classes,
21
+ onClick: handleClick,
22
+ children: props.children
23
+ });
24
+ };
25
+ export { Block };
package/dist/index.js CHANGED
@@ -1,7 +1,8 @@
1
1
  import { deserialize } from "./core/deserialize.js";
2
2
  import { serialize } from "./core/serialize.js";
3
3
  import { defaultValue } from "./defaultValue.js";
4
+ import { useEditorContext } from "./provider.js";
4
5
  import { isEmpty } from "./utils.js";
5
6
  export * from "./editor.js";
6
7
  export * from "./plugins/index.js";
7
- export { defaultValue, deserialize, isEmpty, serialize };
8
+ export { defaultValue, deserialize, isEmpty, serialize, useEditorContext };
@@ -78,7 +78,7 @@ class CodeBlockPlugin {
78
78
  if ('a' === event.key && (event.ctrlKey || event.metaKey) && node && node.type === CodeBlockPlugin.CODE_ELEMENT) {
79
79
  event.preventDefault();
80
80
  const entry = Editor.above(editor, {
81
- match: (n)=>!Editor.isEditor(n) && Element.isElement(n) && n.type === CodeBlockPlugin.CODE_ELEMENT
81
+ match: (n)=>Element.isElement(n) && n.type === CodeBlockPlugin.CODE_ELEMENT
82
82
  });
83
83
  if (entry) {
84
84
  const [, codeBlockPath] = entry;
@@ -1,38 +1,20 @@
1
+ import { jsx } from "react/jsx-runtime";
1
2
  import { useStore } from "@nanostores/react";
2
- import { nanoid } from "nanoid";
3
- import { map } from "nanostores";
4
3
  import { useEffect, useRef, useState } from "react";
5
4
  import { useDrag, useDrop } from "react-dnd";
6
5
  import { NativeTypes } from "react-dnd-html5-backend";
7
- import { Editor, Path, Transforms } from "slate";
6
+ import { Editor, Element, Path, Transforms } from "slate";
8
7
  import { ReactEditor, useReadOnly, useSlate } from "slate-react";
8
+ import { useEditorContext } from "../../provider.js";
9
9
  import { getNodesByNodeIds } from "./utils.js";
10
10
  class DnDPlugin {
11
11
  options;
12
- store;
13
- editors;
14
12
  constructor(options){
15
13
  this.options = options;
16
- this.store = map({
17
- selected: new Set()
18
- });
19
- this.editors = new WeakMap();
20
14
  }
21
15
  init(editor) {
22
- this.editors.set(editor, nanoid());
23
16
  return editor;
24
17
  }
25
- getEditorId(editor) {
26
- return this.editors.get(editor);
27
- }
28
- handleToggleSelected = (nodeId)=>{
29
- const selected = new Set(this.store.get().selected);
30
- if (selected.has(nodeId)) selected.delete(nodeId);
31
- else selected.add(nodeId);
32
- this.store.set({
33
- selected
34
- });
35
- };
36
18
  static DND_BLOCK_ELEMENT = 'block';
37
19
  handlers = {
38
20
  onDrop: (event)=>{
@@ -41,29 +23,35 @@ class DnDPlugin {
41
23
  };
42
24
  renderBlock = (props)=>{
43
25
  const editor = useSlate();
44
- const $store = useStore(this.store);
26
+ const { selectedNodes } = useEditorContext();
27
+ const $selectedNodes = useStore(selectedNodes);
28
+ const isCopying = useRef(false);
45
29
  const options = this.options;
30
+ const generateId = this.options?.nodeIdPlugin?.generateId;
46
31
  const isReadOnly = useReadOnly();
47
32
  const [dropPosition, setDropPosition] = useState(null);
48
33
  const dropTargetRef = useRef(null);
49
- options.customTypes?.[props.element.type];
34
+ const customType = options.customTypes?.[props.element.type];
50
35
  const currentElement = props.element;
51
36
  const [, drag, preview] = useDrag({
52
- type: DnDPlugin.DND_BLOCK_ELEMENT,
37
+ type: customType?.type || DnDPlugin.DND_BLOCK_ELEMENT,
53
38
  item: ()=>{
54
- const selected = Array.from($store.selected.values());
55
- const nodes = selected.length > 0 && selected.includes(currentElement.nodeId) ? getNodesByNodeIds(editor, selected) : [
39
+ const selected = $selectedNodes;
40
+ const nodes = selected.length > 0 && selected.find((node)=>node.nodeId === currentElement.nodeId) ? getNodesByNodeIds(editor, selected.map((node)=>node.nodeId)) : [
56
41
  structuredClone(props.element)
57
42
  ];
43
+ const item = this.options.customTypes?.[currentElement.type]?.getData?.(currentElement);
58
44
  const items = nodes.map((node)=>{
59
45
  if (this.options.customTypes?.[node.type]) return this.options.customTypes[node.type].getData?.(node);
60
46
  return null;
61
47
  }).filter(Boolean);
62
48
  const dragItem = {
49
+ kind: 'inner',
63
50
  nodes,
51
+ item,
64
52
  items,
65
53
  source: {
66
- editorId: this.getEditorId(editor),
54
+ editor,
67
55
  documentId: options.documentId
68
56
  }
69
57
  };
@@ -71,7 +59,7 @@ class DnDPlugin {
71
59
  },
72
60
  canDrag: !isReadOnly,
73
61
  end: ()=>{
74
- $store.selected.clear();
62
+ selectedNodes.set([]);
75
63
  }
76
64
  });
77
65
  const allCustomTypes = Object.values(options.customTypes || {}).map((customType)=>customType.type);
@@ -98,32 +86,47 @@ class DnDPlugin {
98
86
  const hoverClientY = clientOffset.y - hoverBoundingRect.top;
99
87
  hoverClientY < hoverMiddleY ? setDropPosition('top') : setDropPosition('bottom');
100
88
  },
101
- drop (item, monitor) {
89
+ drop: (data, monitor)=>{
102
90
  const itemType = monitor.getItemType();
91
+ const sourceEditor = 'inner' === data.kind ? data.source?.editor : null;
92
+ const isSameDocument = 'inner' === data.kind && data.source?.documentId === this.options.documentId && void 0 !== this.options.documentId;
93
+ const isSameEditor = 'inner' === data.kind && data.source?.editor === editor;
103
94
  const sourceTo = ReactEditor.findPath(editor, props.element);
104
95
  if (!sourceTo) return;
105
96
  const insertAt = getDropPath(editor, sourceTo, dropPosition || 'bottom');
106
97
  if (!insertAt) return;
107
98
  const customDropHandler = itemType && options.customDropHandlers?.[itemType];
108
- if (customDropHandler) return void customDropHandler.onDrop({
99
+ if (customDropHandler && 'outer' === data.kind) return void customDropHandler.onDrop({
109
100
  editor,
110
- item,
101
+ data,
111
102
  insertAt
112
103
  });
113
104
  switch(itemType){
114
105
  case NativeTypes.FILE:
115
- options.onDropFiles(editor, item.files, insertAt);
106
+ options.onDropFiles(editor, data.files, insertAt);
116
107
  break;
117
108
  default:
118
109
  {
119
- const dragItem = item;
110
+ const dragItem = data;
111
+ if ('outer' === dragItem.kind) return;
120
112
  if (!dropPosition || !dragItem.nodes.length) return;
121
113
  const nodeIds = dragItem.nodes.map((node)=>node.nodeId);
122
- moveNode(editor, sourceTo, nodeIds, dropPosition);
123
- $store.selected.clear();
114
+ if (isSameDocument || isSameEditor) if (isCopying.current) {
115
+ if (!generateId) return;
116
+ const clonedNodes = cloneWithNewIds(dragItem.nodes, generateId);
117
+ insertNodes(editor, insertAt, clonedNodes);
118
+ } else moveNode(editor, sourceTo, nodeIds, dropPosition);
119
+ else {
120
+ if (!generateId) return;
121
+ const clonedNodes = cloneWithNewIds(dragItem.nodes, generateId);
122
+ insertNodes(editor, insertAt, clonedNodes);
123
+ if (!isCopying.current && sourceEditor) removeNodes(sourceEditor, nodeIds);
124
+ }
125
+ selectedNodes.set([]);
124
126
  break;
125
127
  }
126
128
  }
129
+ isCopying.current = false;
127
130
  setDropPosition(null);
128
131
  }
129
132
  });
@@ -138,16 +141,27 @@ class DnDPlugin {
138
141
  ]);
139
142
  if (this.options.ignoreNodes?.includes(props.element.type)) return props.children;
140
143
  if (editor.isInline(props.element)) return props.children;
141
- return options.renderBlock?.({
142
- props,
143
- dragRef: drag,
144
- dropRef: connectDropRef,
145
- previewRef: preview,
146
- position: dropPosition,
147
- selected: 'string' == typeof currentElement.nodeId ? $store.selected.has(currentElement.nodeId) : false,
148
- onToggleSelected: ()=>{
149
- if ('string' == typeof currentElement.nodeId) this.handleToggleSelected(currentElement.nodeId);
150
- }
144
+ return /*#__PURE__*/ jsx("div", {
145
+ children: options.renderBlock?.({
146
+ props,
147
+ dragRef: drag,
148
+ dropRef: connectDropRef,
149
+ previewRef: preview,
150
+ position: dropPosition,
151
+ onNativeDrop: (event)=>{
152
+ isCopying.current = event.altKey;
153
+ },
154
+ onToggleSelected: (event)=>{
155
+ event.stopPropagation();
156
+ if ($selectedNodes.includes(props.element)) selectedNodes.set([
157
+ ...$selectedNodes
158
+ ].filter((element)=>element !== props.element));
159
+ else selectedNodes.set([
160
+ ...$selectedNodes,
161
+ props.element
162
+ ]);
163
+ }
164
+ })
151
165
  });
152
166
  };
153
167
  }
@@ -180,4 +194,38 @@ const moveNode = (editor, targetNodePath, nodeIds, position)=>{
180
194
  });
181
195
  Editor.normalize(editor);
182
196
  };
197
+ const insertNodes = (editor, path, nodes)=>{
198
+ Editor.withoutNormalizing(editor, ()=>{
199
+ Transforms.insertNodes(editor, nodes, {
200
+ at: path
201
+ });
202
+ });
203
+ };
204
+ const removeNodes = (editor, nodeIds)=>{
205
+ try {
206
+ Transforms.removeNodes(editor, {
207
+ at: [],
208
+ match: (n)=>{
209
+ if (!Element.isElement(n)) return false;
210
+ if (!Editor.isBlock(editor, n)) return false;
211
+ const node = n;
212
+ return 'string' == typeof node.nodeId && nodeIds.includes(node.nodeId);
213
+ },
214
+ mode: 'highest'
215
+ });
216
+ } catch {
217
+ return;
218
+ }
219
+ };
220
+ const cloneWithNewIds = (nodes, generateId)=>{
221
+ const copy = structuredClone(nodes);
222
+ const assignId = (node)=>{
223
+ node.nodeId = generateId();
224
+ node.children.forEach((node)=>{
225
+ if ('children' in node) assignId(node);
226
+ });
227
+ };
228
+ copy.forEach(assignId);
229
+ return copy;
230
+ };
183
231
  export { DnDPlugin };
@@ -0,0 +1,2 @@
1
+ const isNodeWithId = (node)=>'object' == typeof node && null !== node && 'nodeId' in node;
2
+ export { isNodeWithId };
@@ -85,7 +85,7 @@ const isBlockActive = (editor, type)=>{
85
85
  if (!selection) return false;
86
86
  const [match] = Array.from(Editor.nodes(editor, {
87
87
  at: Editor.unhangRange(editor, selection),
88
- match: (node)=>!Editor.isEditor(node) && Element.isElement(node) && node.type === type
88
+ match: (node)=>Element.isElement(node) && node.type === type
89
89
  }));
90
90
  return !!match;
91
91
  };
@@ -195,7 +195,7 @@ class ListsPlugin {
195
195
  if (!selection) return false;
196
196
  const [match] = Array.from(Editor.nodes(editor, {
197
197
  at: Editor.unhangRange(editor, selection),
198
- match: (node)=>!Editor.isEditor(node) && Element.isElement(node) && node.type === type
198
+ match: (node)=>Element.isElement(node) && node.type === type
199
199
  }));
200
200
  return !!match;
201
201
  };
@@ -10,8 +10,10 @@ const assignId = (node, generateId)=>{
10
10
  };
11
11
  class NodeIdPlugin {
12
12
  options;
13
+ generateId;
13
14
  constructor(options){
14
15
  this.options = options;
16
+ this.generateId = options.generateId;
15
17
  }
16
18
  init(editor) {
17
19
  const { apply, normalizeNode } = editor;
@@ -20,22 +22,22 @@ class NodeIdPlugin {
20
22
  const node = Node.get(editor, operation.path);
21
23
  const oldType = operation.properties.type;
22
24
  const newType = operation.newProperties.type;
23
- if (!node || !Text.isText(node) && oldType !== newType) operation.newProperties.nodeId = this.options.generateId();
25
+ if (!node || !Text.isText(node) && oldType !== newType) operation.newProperties.nodeId = this.generateId();
24
26
  return apply(operation);
25
27
  }
26
28
  if ('insert_node' === operation.type) {
27
- assignId(operation.node, this.options.generateId);
29
+ assignId(operation.node, this.generateId);
28
30
  return apply(operation);
29
31
  }
30
32
  if ('split_node' === operation.type) {
31
33
  const node = Node.get(editor, operation.path);
32
- if (!node || !Text.isText(node)) operation.properties.nodeId = this.options.generateId();
34
+ if (!node || !Text.isText(node)) operation.properties.nodeId = this.generateId();
33
35
  }
34
36
  return apply(operation);
35
37
  };
36
38
  editor.normalizeNode = (entry)=>{
37
39
  const [node] = entry;
38
- assignId(node, this.options.generateId);
40
+ assignId(node, this.generateId);
39
41
  normalizeNode(entry);
40
42
  };
41
43
  return editor;
@@ -0,0 +1,15 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { createContext, useContext } from "react";
3
+ const Context = /*#__PURE__*/ createContext(null);
4
+ const EditorProvider = ({ children, selectedNodes })=>/*#__PURE__*/ jsx(Context.Provider, {
5
+ value: {
6
+ selectedNodes
7
+ },
8
+ children: children
9
+ });
10
+ const useEditorContext = ()=>{
11
+ const context = useContext(Context);
12
+ if (!context) throw new Error('useEditorContext must be used within an EditorProvider');
13
+ return context;
14
+ };
15
+ export { EditorProvider, useEditorContext };
@@ -1,4 +1,4 @@
1
- import { type Editor } from 'slate';
1
+ import { Editor } from 'slate';
2
2
  import type { IPlugin } from '../types';
3
3
  type Props = {
4
4
  readOnly?: boolean;
@@ -0,0 +1,2 @@
1
+ import { type RenderElementProps } from 'slate-react';
2
+ export declare const Block: (props: RenderElementProps) => import("react/jsx-runtime").JSX.Element;
@@ -4,5 +4,6 @@ export { serialize } from './core/serialize';
4
4
  export { defaultValue } from './defaultValue';
5
5
  export * from './editor';
6
6
  export * from './plugins';
7
+ export { useEditorContext } from './provider';
7
8
  export type { EditorRef, IPlugin } from './types';
8
9
  export { isEmpty } from './utils';
@@ -1,20 +1,13 @@
1
- import { type MapStore } from 'nanostores';
2
1
  import { Editor } from 'slate';
3
2
  import { ReactEditor, type RenderElementProps } from 'slate-react';
4
3
  import type { IPlugin } from '../../types';
5
4
  import type { Options } from './types';
6
5
  export declare class DnDPlugin implements IPlugin {
7
6
  private options;
8
- store: MapStore<{
9
- selected: Set<string>;
10
- }>;
11
- editors: WeakMap<Editor, string>;
12
7
  constructor(options: Options);
13
8
  init(editor: Editor): import("slate").BaseEditor & ReactEditor & {
14
9
  getCommands: <T extends IPlugin>(plugin: new () => T) => T["commands"];
15
10
  };
16
- getEditorId(editor: Editor): string | undefined;
17
- handleToggleSelected: (nodeId: string) => void;
18
11
  static DND_BLOCK_ELEMENT: string;
19
12
  handlers: {
20
13
  onDrop: (event: DragEvent) => void;