@use-kona/editor 0.1.10 → 0.1.12

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.
@@ -59,8 +59,9 @@ class ListsPlugin {
59
59
  if (prevList) {
60
60
  const currentDepth = this.getListDepth(editor, path);
61
61
  const prevDepth = this.getListDepth(editor, prevList[1]);
62
- if (this.isList(editor, prevList[0]) && currentDepth === prevDepth) try {
62
+ if (this.isList(editor, prevList[0]) && currentDepth === prevDepth && prevList[0].type === node.type) try {
63
63
  Transforms.mergeNodes(editor, {
64
+ at: path,
64
65
  match: (n)=>this.isList(editor, n)
65
66
  });
66
67
  } catch (e) {}
@@ -225,16 +226,26 @@ class ListsPlugin {
225
226
  ].includes(n.type)
226
227
  });
227
228
  else {
228
- Transforms.setNodes(editor, {
229
- type: listItemType
230
- }, {
231
- mode: 'lowest'
232
- });
229
+ const { selection } = editor;
230
+ if (!selection) return;
231
+ const nodes = Array.from(Editor.nodes(editor, {
232
+ at: Editor.unhangRange(editor, selection),
233
+ match: (n)=>Element.isElement(n),
234
+ mode: 'highest'
235
+ }));
236
+ if (!nodes.length) return;
233
237
  Transforms.wrapNodes(editor, {
234
238
  type: listType,
235
239
  children: []
236
240
  }, {
237
- match: (n)=>n.type === listItemType
241
+ mode: 'highest',
242
+ match: (n)=>Element.isElement(n) && n.type === listItemType
243
+ });
244
+ Transforms.setNodes(editor, {
245
+ type: listItemType
246
+ }, {
247
+ at: nodes[0][1],
248
+ split: true
238
249
  });
239
250
  }
240
251
  });
@@ -0,0 +1,3 @@
1
+ /** @jsxRuntime classic */
2
+ /** @jsx jsx */
3
+ export {};
@@ -0,0 +1,47 @@
1
+ import { createHyperscript, createText } from "slate-hyperscript";
2
+ import { describe, expect, it } from "vitest";
3
+ import { createEditor } from "../../core/createEditor.js";
4
+ import { ListsPlugin } from "./ListsPlugin.js";
5
+ const ListsPlugin_spec_elements = {
6
+ paragraph: {
7
+ type: 'paragraph'
8
+ },
9
+ numberedList: {
10
+ type: ListsPlugin.NUMBERED_LIST_ELEMENT
11
+ },
12
+ bulletedList: {
13
+ type: ListsPlugin.BULLETED_LIST_ELEMENT
14
+ },
15
+ listItem: {
16
+ type: ListsPlugin.LIST_ITEM_ELEMENT
17
+ }
18
+ };
19
+ const jsx = createHyperscript({
20
+ elements: ListsPlugin_spec_elements,
21
+ creators: {
22
+ text: createText
23
+ }
24
+ });
25
+ const createEditorWithPlugin = (children)=>{
26
+ const editorState = /*#__PURE__*/ jsx("editor", null, children);
27
+ const editor = createEditor([
28
+ new ListsPlugin()
29
+ ])();
30
+ editor.children = editorState.children;
31
+ editor.selection = editorState.selection;
32
+ return editor;
33
+ };
34
+ describe('ListsPlugin', ()=>{
35
+ it('should change current block to bulleted list', ()=>{
36
+ const editor = createEditorWithPlugin(/*#__PURE__*/ jsx("paragraph", null, /*#__PURE__*/ jsx("cursor", null), /*#__PURE__*/ jsx("text", null, "Hello world")));
37
+ ListsPlugin.toggleList(editor, ListsPlugin.BULLETED_LIST_ELEMENT);
38
+ const output = /*#__PURE__*/ jsx("editor", null, /*#__PURE__*/ jsx("bulletedList", null, /*#__PURE__*/ jsx("listItem", null, /*#__PURE__*/ jsx("text", null, "Hello world"))), /*#__PURE__*/ jsx("paragraph", null, /*#__PURE__*/ jsx("text", null)));
39
+ expect(editor.children).toEqual(output.children);
40
+ });
41
+ it('should change current block to numbered list', ()=>{
42
+ const editor = createEditorWithPlugin(/*#__PURE__*/ jsx("paragraph", null, /*#__PURE__*/ jsx("cursor", null), /*#__PURE__*/ jsx("text", null, "Hello world")));
43
+ ListsPlugin.toggleList(editor, ListsPlugin.NUMBERED_LIST_ELEMENT);
44
+ const output = /*#__PURE__*/ jsx("editor", null, /*#__PURE__*/ jsx("numberedList", null, /*#__PURE__*/ jsx("listItem", null, /*#__PURE__*/ jsx("text", null, "Hello world"))), /*#__PURE__*/ jsx("paragraph", null, /*#__PURE__*/ jsx("text", null)));
45
+ expect(editor.children).toEqual(output.children);
46
+ });
47
+ });
@@ -50,7 +50,7 @@ class TableOfContentsPlugin {
50
50
  const element = ReactEditor.toDOMNode(params.editor, node);
51
51
  element?.scrollIntoView({
52
52
  behavior: 'smooth',
53
- block: 'nearest'
53
+ block: 'start'
54
54
  });
55
55
  };
56
56
  return /*#__PURE__*/ jsx("div", {
@@ -3,6 +3,12 @@
3
3
  position: absolute;
4
4
  top: 50px;
5
5
  right: 8px;
6
+
7
+ &:after {
8
+ content: "";
9
+ position: absolute;
10
+ inset: -8px 0 -8px -8px;
11
+ }
6
12
  }
7
13
 
8
14
  .toc-MJmvGk .max-NR6DEL {
@@ -19,6 +25,7 @@
19
25
 
20
26
  .mini-iQ6Zfx {
21
27
  transform-origin: 100% 0;
28
+ opacity: .65;
22
29
  flex-direction: column;
23
30
  align-items: flex-end;
24
31
  gap: 4px;
@@ -50,6 +57,7 @@
50
57
  transform-origin: 100% 0;
51
58
  border-radius: 4px;
52
59
  width: max-content;
60
+ min-width: 120px;
53
61
  max-width: 200px;
54
62
  max-height: 160px;
55
63
  padding: 4px;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@use-kona/editor",
3
- "version": "0.1.10",
3
+ "version": "0.1.12",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./src/index.ts"
@@ -44,15 +44,15 @@
44
44
  "react-dnd": "^16.0.1",
45
45
  "react-dnd-html5-backend": "^16.0.1",
46
46
  "react-dom": "18",
47
+ "slate": "^0.117.2",
48
+ "slate-history": "^0.113.1",
49
+ "slate-hyperscript": "^0.100.0",
50
+ "slate-react": "^0.117.3",
47
51
  "storybook": "^9.0.13",
48
52
  "storybook-addon-rslib": "^2.0.2",
49
53
  "storybook-react-rsbuild": "^2.0.2",
50
54
  "typescript": "^5.8.3",
51
- "vitest": "^3.2.4",
52
- "slate": "^0.117.2",
53
- "slate-history": "^0.113.1",
54
- "slate-hyperscript": "^0.100.0",
55
- "slate-react": "^0.117.3"
55
+ "vitest": "^3.2.4"
56
56
  },
57
57
  "peerDependencies": {
58
58
  "react": ">=16.9.0",
@@ -0,0 +1,85 @@
1
+ /** @jsxRuntime classic */
2
+ /** @jsx jsx */
3
+
4
+ import {
5
+ createHyperscript,
6
+ createText,
7
+ HyperscriptShorthands,
8
+ } from 'slate-hyperscript';
9
+ import { describe, expect, it } from 'vitest';
10
+ import { createEditor } from '../../core/createEditor';
11
+ import { ListsPlugin } from './ListsPlugin';
12
+
13
+ const elements: HyperscriptShorthands = {
14
+ paragraph: { type: 'paragraph' },
15
+ numberedList: { type: ListsPlugin.NUMBERED_LIST_ELEMENT },
16
+ bulletedList: { type: ListsPlugin.BULLETED_LIST_ELEMENT },
17
+ listItem: { type: ListsPlugin.LIST_ITEM_ELEMENT },
18
+ };
19
+
20
+ const jsx = createHyperscript({ elements, creators: { text: createText } });
21
+
22
+ jsx;
23
+
24
+ const createEditorWithPlugin = (children: any) => {
25
+ const editorState = <editor>{children}</editor>;
26
+ const editor = createEditor([new ListsPlugin()])();
27
+ editor.children = editorState.children;
28
+ editor.selection = editorState.selection;
29
+
30
+ return editor;
31
+ };
32
+
33
+ describe('ListsPlugin', () => {
34
+ it('should change current block to bulleted list', () => {
35
+ const editor = createEditorWithPlugin(
36
+ <paragraph>
37
+ <cursor />
38
+ <text>Hello world</text>
39
+ </paragraph>,
40
+ );
41
+
42
+ ListsPlugin.toggleList(editor, ListsPlugin.BULLETED_LIST_ELEMENT);
43
+
44
+ const output = (
45
+ <editor>
46
+ <bulletedList>
47
+ <listItem>
48
+ <text>Hello world</text>
49
+ </listItem>
50
+ </bulletedList>
51
+ <paragraph>
52
+ <text></text>
53
+ </paragraph>
54
+ </editor>
55
+ );
56
+
57
+ expect(editor.children).toEqual(output.children);
58
+ });
59
+
60
+ it('should change current block to numbered list', () => {
61
+ const editor = createEditorWithPlugin(
62
+ <paragraph>
63
+ <cursor />
64
+ <text>Hello world</text>
65
+ </paragraph>,
66
+ );
67
+
68
+ ListsPlugin.toggleList(editor, ListsPlugin.NUMBERED_LIST_ELEMENT);
69
+
70
+ const output = (
71
+ <editor>
72
+ <numberedList>
73
+ <listItem>
74
+ <text>Hello world</text>
75
+ </listItem>
76
+ </numberedList>
77
+ <paragraph>
78
+ <text></text>
79
+ </paragraph>
80
+ </editor>
81
+ );
82
+
83
+ expect(editor.children).toEqual(output.children);
84
+ });
85
+ });
@@ -44,7 +44,7 @@ export class ListsPlugin implements IPlugin {
44
44
 
45
45
  editor.normalizeNode = (entry: NodeEntry) => {
46
46
  const [node, path] = entry;
47
-
47
+ //
48
48
  if (this.isList(editor, node as CustomElement)) {
49
49
  /* Unwrap lists around non-list-items */
50
50
  for (const [child, childPath] of Array.from(
@@ -99,7 +99,7 @@ export class ListsPlugin implements IPlugin {
99
99
 
100
100
  const prevList =
101
101
  prevListItemPath &&
102
- Editor.above(editor, {
102
+ Editor.above<CustomElement>(editor, {
103
103
  at: prevListItemPath,
104
104
  match: (n) => this.isList(editor, n as CustomElement),
105
105
  });
@@ -110,10 +110,12 @@ export class ListsPlugin implements IPlugin {
110
110
 
111
111
  if (
112
112
  this.isList(editor, prevList[0] as CustomElement) &&
113
- currentDepth === prevDepth
113
+ currentDepth === prevDepth &&
114
+ prevList[0].type === (node as CustomElement).type
114
115
  ) {
115
116
  try {
116
117
  Transforms.mergeNodes(editor, {
118
+ at: path,
117
119
  match: (n) => this.isList(editor, n as CustomElement),
118
120
  });
119
121
  } catch (e) {}
@@ -395,11 +397,39 @@ export class ListsPlugin implements IPlugin {
395
397
  },
396
398
  );
397
399
  } else {
398
- Transforms.setNodes(editor, { type: listItemType }, { mode: 'lowest' });
400
+ const { selection } = editor;
401
+
402
+ if (!selection) {
403
+ return;
404
+ }
405
+
406
+ const nodes = Array.from(
407
+ Editor.nodes(editor, {
408
+ at: Editor.unhangRange(editor, selection),
409
+ match: (n) => Element.isElement(n),
410
+ mode: 'highest',
411
+ }),
412
+ );
413
+
414
+ if (!nodes.length) {
415
+ return;
416
+ }
417
+
399
418
  Transforms.wrapNodes(
400
419
  editor,
401
420
  { type: listType, children: [] },
402
- { match: (n) => (n as CustomElement).type === listItemType },
421
+ {
422
+ mode: 'highest',
423
+ match: (n) => {
424
+ return Element.isElement(n) && n.type === listItemType;
425
+ },
426
+ },
427
+ );
428
+
429
+ Transforms.setNodes(
430
+ editor,
431
+ { type: listItemType },
432
+ { at: nodes[0][1], split: true },
403
433
  );
404
434
  }
405
435
  });
@@ -77,7 +77,7 @@ export class TableOfContentsPlugin implements IPlugin {
77
77
  ) as HTMLElement;
78
78
  element?.scrollIntoView({
79
79
  behavior: 'smooth',
80
- block: 'nearest'
80
+ block: 'start',
81
81
  });
82
82
  };
83
83
 
@@ -3,6 +3,15 @@
3
3
  top: 50px;
4
4
  right: 8px;
5
5
  z-index: 3;
6
+
7
+ &:after {
8
+ content: "";
9
+ position: absolute;
10
+ top: -8px;
11
+ left: -8px;
12
+ bottom: -8px;
13
+ right: 0;
14
+ }
6
15
  }
7
16
 
8
17
  .toc .max {
@@ -24,6 +33,7 @@
24
33
  gap: 4px;
25
34
  transition: all 0.25s;
26
35
  transform-origin: top right;
36
+ opacity: 0.65;
27
37
  }
28
38
 
29
39
  .mini .h1 {
@@ -55,6 +65,7 @@
55
65
  transition: all 0.25s;
56
66
  transform-origin: top right;
57
67
  width: max-content;
68
+ min-width: 120px;
58
69
  max-width: 200px;
59
70
  max-height: 160px;
60
71
  overflow-y: auto;