@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.
- package/dist/plugins/ListsPlugin/ListsPlugin.js +18 -7
- package/dist/plugins/ListsPlugin/ListsPlugin.spec.d.ts +3 -0
- package/dist/plugins/ListsPlugin/ListsPlugin.spec.js +47 -0
- package/dist/plugins/TableOfContentsPlugin/TableOfContentsPlugin.js +1 -1
- package/dist/plugins/TableOfContentsPlugin/styles_module.css +8 -0
- package/package.json +6 -6
- package/src/plugins/ListsPlugin/ListsPlugin.spec.tsx +85 -0
- package/src/plugins/ListsPlugin/ListsPlugin.tsx +35 -5
- package/src/plugins/TableOfContentsPlugin/TableOfContentsPlugin.tsx +1 -1
- package/src/plugins/TableOfContentsPlugin/styles.module.css +11 -0
|
@@ -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
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
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
|
-
|
|
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,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
|
+
});
|
|
@@ -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.
|
|
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
|
-
|
|
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
|
-
{
|
|
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
|
});
|
|
@@ -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;
|