@use-kona/editor 0.1.25 → 0.1.26
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.
|
@@ -8,8 +8,9 @@ class ListsPlugin {
|
|
|
8
8
|
static NUMBERED_LIST_ELEMENT = 'ol';
|
|
9
9
|
static LIST_ITEM_ELEMENT = 'li';
|
|
10
10
|
constructor(options = {}){
|
|
11
|
-
const { listTypes = [], listItemTypes = [] } = options;
|
|
11
|
+
const { ignoreBackspaceTypes = [], listTypes = [], listItemTypes = [] } = options;
|
|
12
12
|
this.options = {
|
|
13
|
+
ignoreBackspaceTypes,
|
|
13
14
|
listTypes: [
|
|
14
15
|
ListsPlugin.BULLETED_LIST_ELEMENT,
|
|
15
16
|
ListsPlugin.NUMBERED_LIST_ELEMENT,
|
|
@@ -139,7 +140,8 @@ class ListsPlugin {
|
|
|
139
140
|
match: (n)=>this.isListItem(editor, n)
|
|
140
141
|
}));
|
|
141
142
|
if ('Backspace' === event.key) {
|
|
142
|
-
if (selection && match && 1 === this.getListItemDepth(editor, match[1]) && Editor.isStart(editor, selection.anchor, match[1])) {
|
|
143
|
+
if (selection && match && !this.options.ignoreBackspaceTypes?.includes(match[0].type) && 1 === this.getListItemDepth(editor, match[1]) && Editor.isStart(editor, selection.anchor, match[1])) {
|
|
144
|
+
event.preventDefault();
|
|
143
145
|
Transforms.unwrapNodes(editor, {
|
|
144
146
|
match: (n)=>this.isList(editor, n),
|
|
145
147
|
split: true
|
package/package.json
CHANGED
|
@@ -1,35 +1,44 @@
|
|
|
1
1
|
/** @jsxRuntime classic */
|
|
2
2
|
/** @jsx jsx */
|
|
3
3
|
|
|
4
|
+
import type { KeyboardEvent, ReactNode } from 'react';
|
|
5
|
+
import { Editor } from 'slate';
|
|
4
6
|
import {
|
|
5
7
|
createHyperscript,
|
|
6
8
|
createText,
|
|
7
9
|
type HyperscriptShorthands,
|
|
8
10
|
} from 'slate-hyperscript';
|
|
9
|
-
import { describe, expect, it } from 'vitest';
|
|
10
|
-
import { Editor } from 'slate';
|
|
11
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
11
12
|
import { createEditor } from '../../core/createEditor';
|
|
12
13
|
import { ListsPlugin } from './ListsPlugin';
|
|
13
14
|
|
|
14
|
-
|
|
15
15
|
const elements: HyperscriptShorthands = {
|
|
16
16
|
paragraph: { type: 'paragraph' },
|
|
17
17
|
numberedList: { type: ListsPlugin.NUMBERED_LIST_ELEMENT },
|
|
18
18
|
bulletedList: { type: ListsPlugin.BULLETED_LIST_ELEMENT },
|
|
19
19
|
listItem: { type: ListsPlugin.LIST_ITEM_ELEMENT },
|
|
20
|
+
taskItem: { type: 'task-item' },
|
|
20
21
|
};
|
|
21
22
|
|
|
22
23
|
const jsx = createHyperscript({ elements, creators: { text: createText } });
|
|
23
24
|
|
|
24
25
|
jsx;
|
|
25
26
|
|
|
26
|
-
const
|
|
27
|
+
const createEditorAndPlugin = (
|
|
28
|
+
children: ReactNode,
|
|
29
|
+
options: ConstructorParameters<typeof ListsPlugin>[0] = {},
|
|
30
|
+
) => {
|
|
27
31
|
const editorState = <editor>{children}</editor>;
|
|
28
|
-
const
|
|
32
|
+
const plugin = new ListsPlugin(options);
|
|
33
|
+
const editor = createEditor([plugin])();
|
|
29
34
|
editor.children = editorState.children;
|
|
30
35
|
editor.selection = editorState.selection;
|
|
31
36
|
|
|
32
|
-
return editor;
|
|
37
|
+
return { editor, plugin };
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const createEditorWithPlugin = (children: ReactNode) => {
|
|
41
|
+
return createEditorAndPlugin(children).editor;
|
|
33
42
|
};
|
|
34
43
|
|
|
35
44
|
describe('ListsPlugin', () => {
|
|
@@ -128,13 +137,19 @@ describe('ListsPlugin', () => {
|
|
|
128
137
|
{
|
|
129
138
|
type: ListsPlugin.NUMBERED_LIST_ELEMENT,
|
|
130
139
|
children: [
|
|
131
|
-
{
|
|
140
|
+
{
|
|
141
|
+
type: ListsPlugin.LIST_ITEM_ELEMENT,
|
|
142
|
+
children: [{ text: 'first' }],
|
|
143
|
+
},
|
|
132
144
|
],
|
|
133
145
|
},
|
|
134
146
|
{
|
|
135
147
|
type: ListsPlugin.NUMBERED_LIST_ELEMENT,
|
|
136
148
|
children: [
|
|
137
|
-
{
|
|
149
|
+
{
|
|
150
|
+
type: ListsPlugin.LIST_ITEM_ELEMENT,
|
|
151
|
+
children: [{ text: 'second' }],
|
|
152
|
+
},
|
|
138
153
|
],
|
|
139
154
|
},
|
|
140
155
|
];
|
|
@@ -146,8 +161,14 @@ describe('ListsPlugin', () => {
|
|
|
146
161
|
{
|
|
147
162
|
type: ListsPlugin.NUMBERED_LIST_ELEMENT,
|
|
148
163
|
children: [
|
|
149
|
-
{
|
|
150
|
-
|
|
164
|
+
{
|
|
165
|
+
type: ListsPlugin.LIST_ITEM_ELEMENT,
|
|
166
|
+
children: [{ text: 'first' }],
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
type: ListsPlugin.LIST_ITEM_ELEMENT,
|
|
170
|
+
children: [{ text: 'second' }],
|
|
171
|
+
},
|
|
151
172
|
],
|
|
152
173
|
},
|
|
153
174
|
];
|
|
@@ -166,13 +187,19 @@ describe('ListsPlugin', () => {
|
|
|
166
187
|
{
|
|
167
188
|
type: ListsPlugin.BULLETED_LIST_ELEMENT,
|
|
168
189
|
children: [
|
|
169
|
-
{
|
|
190
|
+
{
|
|
191
|
+
type: ListsPlugin.LIST_ITEM_ELEMENT,
|
|
192
|
+
children: [{ text: 'bullet' }],
|
|
193
|
+
},
|
|
170
194
|
],
|
|
171
195
|
},
|
|
172
196
|
{
|
|
173
197
|
type: ListsPlugin.NUMBERED_LIST_ELEMENT,
|
|
174
198
|
children: [
|
|
175
|
-
{
|
|
199
|
+
{
|
|
200
|
+
type: ListsPlugin.LIST_ITEM_ELEMENT,
|
|
201
|
+
children: [{ text: 'number' }],
|
|
202
|
+
},
|
|
176
203
|
],
|
|
177
204
|
},
|
|
178
205
|
];
|
|
@@ -184,13 +211,19 @@ describe('ListsPlugin', () => {
|
|
|
184
211
|
{
|
|
185
212
|
type: ListsPlugin.BULLETED_LIST_ELEMENT,
|
|
186
213
|
children: [
|
|
187
|
-
{
|
|
214
|
+
{
|
|
215
|
+
type: ListsPlugin.LIST_ITEM_ELEMENT,
|
|
216
|
+
children: [{ text: 'bullet' }],
|
|
217
|
+
},
|
|
188
218
|
],
|
|
189
219
|
},
|
|
190
220
|
{
|
|
191
221
|
type: ListsPlugin.NUMBERED_LIST_ELEMENT,
|
|
192
222
|
children: [
|
|
193
|
-
{
|
|
223
|
+
{
|
|
224
|
+
type: ListsPlugin.LIST_ITEM_ELEMENT,
|
|
225
|
+
children: [{ text: 'number' }],
|
|
226
|
+
},
|
|
194
227
|
],
|
|
195
228
|
},
|
|
196
229
|
];
|
|
@@ -242,4 +275,67 @@ describe('ListsPlugin', () => {
|
|
|
242
275
|
|
|
243
276
|
expect(editor.children).toEqual(output);
|
|
244
277
|
});
|
|
278
|
+
|
|
279
|
+
it('should turn first-level list item into paragraph on Backspace at start', () => {
|
|
280
|
+
const { editor, plugin } = createEditorAndPlugin(
|
|
281
|
+
<bulletedList>
|
|
282
|
+
<listItem>
|
|
283
|
+
<cursor />
|
|
284
|
+
<text>Hello world</text>
|
|
285
|
+
</listItem>
|
|
286
|
+
</bulletedList>,
|
|
287
|
+
);
|
|
288
|
+
const event = {
|
|
289
|
+
key: 'Backspace',
|
|
290
|
+
preventDefault: vi.fn(),
|
|
291
|
+
} as unknown as KeyboardEvent;
|
|
292
|
+
|
|
293
|
+
plugin.handlers.onKeyDown(event, editor);
|
|
294
|
+
|
|
295
|
+
const output = (
|
|
296
|
+
<editor>
|
|
297
|
+
<paragraph>
|
|
298
|
+
<text>Hello world</text>
|
|
299
|
+
</paragraph>
|
|
300
|
+
</editor>
|
|
301
|
+
);
|
|
302
|
+
|
|
303
|
+
expect(event.preventDefault).toHaveBeenCalledOnce();
|
|
304
|
+
expect(editor.children).toEqual(output.children);
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
it('should ignore configured list item types for Backspace conversion', () => {
|
|
308
|
+
const { editor, plugin } = createEditorAndPlugin(
|
|
309
|
+
<bulletedList>
|
|
310
|
+
<taskItem>
|
|
311
|
+
<cursor />
|
|
312
|
+
<text>Hello world</text>
|
|
313
|
+
</taskItem>
|
|
314
|
+
</bulletedList>,
|
|
315
|
+
{
|
|
316
|
+
ignoreBackspaceTypes: ['task-item'],
|
|
317
|
+
listItemTypes: ['task-item'],
|
|
318
|
+
},
|
|
319
|
+
);
|
|
320
|
+
const event = {
|
|
321
|
+
key: 'Backspace',
|
|
322
|
+
preventDefault: vi.fn(),
|
|
323
|
+
} as unknown as KeyboardEvent;
|
|
324
|
+
|
|
325
|
+
plugin.handlers.onKeyDown(event, editor);
|
|
326
|
+
|
|
327
|
+
const output = (
|
|
328
|
+
<editor>
|
|
329
|
+
<bulletedList>
|
|
330
|
+
<taskItem>
|
|
331
|
+
<text />
|
|
332
|
+
<text>Hello world</text>
|
|
333
|
+
</taskItem>
|
|
334
|
+
</bulletedList>
|
|
335
|
+
</editor>
|
|
336
|
+
);
|
|
337
|
+
|
|
338
|
+
expect(event.preventDefault).not.toHaveBeenCalled();
|
|
339
|
+
expect(editor.children).toEqual(output.children);
|
|
340
|
+
});
|
|
245
341
|
});
|
|
@@ -17,6 +17,7 @@ import styles from './styles.module.css';
|
|
|
17
17
|
type Options = {
|
|
18
18
|
listTypes?: string[];
|
|
19
19
|
listItemTypes?: string[];
|
|
20
|
+
ignoreBackspaceTypes?: string[];
|
|
20
21
|
};
|
|
21
22
|
|
|
22
23
|
export class ListsPlugin implements IPlugin {
|
|
@@ -27,9 +28,14 @@ export class ListsPlugin implements IPlugin {
|
|
|
27
28
|
static LIST_ITEM_ELEMENT = 'li';
|
|
28
29
|
|
|
29
30
|
constructor(options: Options = {}) {
|
|
30
|
-
const {
|
|
31
|
+
const {
|
|
32
|
+
ignoreBackspaceTypes = [],
|
|
33
|
+
listTypes = [],
|
|
34
|
+
listItemTypes = [],
|
|
35
|
+
} = options;
|
|
31
36
|
|
|
32
37
|
this.options = {
|
|
38
|
+
ignoreBackspaceTypes,
|
|
33
39
|
listTypes: [
|
|
34
40
|
ListsPlugin.BULLETED_LIST_ELEMENT,
|
|
35
41
|
ListsPlugin.NUMBERED_LIST_ELEMENT,
|
|
@@ -239,9 +245,14 @@ export class ListsPlugin implements IPlugin {
|
|
|
239
245
|
if (
|
|
240
246
|
selection &&
|
|
241
247
|
match &&
|
|
248
|
+
!this.options.ignoreBackspaceTypes?.includes(
|
|
249
|
+
(match[0] as CustomElement).type,
|
|
250
|
+
) &&
|
|
242
251
|
this.getListItemDepth(editor, match[1]) === 1 &&
|
|
243
252
|
Editor.isStart(editor, selection.anchor, match[1])
|
|
244
253
|
) {
|
|
254
|
+
event.preventDefault();
|
|
255
|
+
|
|
245
256
|
Transforms.unwrapNodes(editor, {
|
|
246
257
|
match: (n) => this.isList(editor, n as CustomElement),
|
|
247
258
|
split: true,
|