@lofcz/platejs-list 52.0.11

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.
@@ -0,0 +1,803 @@
1
+ import { c } from "react-compiler-runtime";
2
+ import React from "react";
3
+ import { KEYS, NodeApi, PathApi, createTSlatePlugin, getInjectMatch, isDefined, isHtmlBlockElement, postCleanHtml, traverseHtmlElements } from "platejs";
4
+ import { setIndent } from "@platejs/indent";
5
+
6
+ //#region src/lib/types.ts
7
+ const ListStyleType = {
8
+ ArabicIndic: "arabic-indic",
9
+ Armenian: "armenian",
10
+ Bengali: "bengali",
11
+ Cambodian: "cambodian",
12
+ Circle: "circle",
13
+ CjkDecimal: "cjk-decimal",
14
+ CjkEarthlyBranch: "cjk-earthly-branch",
15
+ CjkHeavenlyStem: "cjk-heavenly-stem",
16
+ Decimal: "decimal",
17
+ DecimalLeadingZero: "decimal-leading-zero",
18
+ Devanagari: "devanagari",
19
+ Disc: "disc",
20
+ DisclosureClosed: "disclosure-closed",
21
+ DisclosureOpen: "disclosure-open",
22
+ EthiopicNumeric: "ethiopic-numeric",
23
+ Georgian: "georgian",
24
+ Gujarati: "gujarati",
25
+ Gurmukhi: "gurmukhi",
26
+ Hebrew: "hebrew",
27
+ Hiragana: "hiragana",
28
+ HiraganaIroha: "hiragana-iroha",
29
+ Inherit: "inherit",
30
+ Initial: "initial",
31
+ JapaneseFormal: "japanese-formal",
32
+ JapaneseInformal: "japanese-informal",
33
+ Kannada: "kannada",
34
+ Katakana: "katakana",
35
+ KatakanaIroha: "katakana-iroha",
36
+ Khmer: "khmer",
37
+ KoreanHangulFormal: "korean-hangul-formal",
38
+ KoreanHanjaFormal: "korean-hanja-formal",
39
+ KoreanHanjaInformal: "korean-hanja-informal",
40
+ Lao: "lao",
41
+ LowerAlpha: "lower-alpha",
42
+ LowerArmenian: "lower-armenian",
43
+ LowerGreek: "lower-greek",
44
+ LowerLatin: "lower-latin",
45
+ LowerRoman: "lower-roman",
46
+ Malayalam: "malayalam",
47
+ Mongolian: "mongolian",
48
+ Myanmar: "myanmar",
49
+ None: "none",
50
+ Oriya: "oriya",
51
+ Persian: "persian",
52
+ SimpChineseFormal: "simp-chinese-formal",
53
+ SimpChineseInformal: "simp-chinese-informal",
54
+ Square: "square",
55
+ Tamil: "tamil",
56
+ Telugu: "telugu",
57
+ Thai: "thai",
58
+ Tibetan: "tibetan",
59
+ TradChineseFormal: "trad-chinese-formal",
60
+ TradChineseInformal: "trad-chinese-informal",
61
+ UpperAlpha: "upper-alpha",
62
+ UpperArmenian: "upper-armenian",
63
+ UpperLatin: "upper-latin",
64
+ UpperRoman: "upper-roman"
65
+ };
66
+ const ULIST_STYLE_TYPES = [
67
+ ListStyleType.Disc,
68
+ ListStyleType.Circle,
69
+ ListStyleType.Square,
70
+ ListStyleType.DisclosureOpen,
71
+ ListStyleType.DisclosureClosed
72
+ ];
73
+
74
+ //#endregion
75
+ //#region src/lib/queries/areEqListStyleType.ts
76
+ const areEqListStyleType = (_editor, entries, { listStyleType = ListStyleType.Disc }) => {
77
+ let eqListStyleType = true;
78
+ for (const entry of entries) {
79
+ const [block] = entry;
80
+ if (listStyleType === KEYS.listTodo) {
81
+ if (!Object.hasOwn(block, KEYS.listChecked)) {
82
+ eqListStyleType = false;
83
+ break;
84
+ }
85
+ continue;
86
+ }
87
+ if (!block[KEYS.listType] || block[KEYS.listType] !== listStyleType) {
88
+ eqListStyleType = false;
89
+ break;
90
+ }
91
+ }
92
+ return eqListStyleType;
93
+ };
94
+
95
+ //#endregion
96
+ //#region src/lib/queries/getListChildren.ts
97
+ /**
98
+ * Get all list items that are children of the current list item (have bigger
99
+ * indent). Stops when encountering an item with equal or lower indent.
100
+ */
101
+ const getListChildren = (editor, entry) => {
102
+ const children = [];
103
+ const [node, path] = entry;
104
+ const parentIndent = node[KEYS.indent];
105
+ if (!isDefined(parentIndent) || !isDefined(node[KEYS.listType])) return children;
106
+ let currentPath = path;
107
+ while (true) {
108
+ const nextPath = PathApi.next(currentPath);
109
+ if (!nextPath) break;
110
+ const nextNode = NodeApi.get(editor, nextPath);
111
+ if (!nextNode) break;
112
+ const nextIndent = nextNode[KEYS.indent];
113
+ if (!isDefined(nextIndent) || !isDefined(nextNode[KEYS.listType])) break;
114
+ if (nextIndent <= parentIndent) break;
115
+ children.push([nextNode, nextPath]);
116
+ currentPath = nextPath;
117
+ }
118
+ return children;
119
+ };
120
+
121
+ //#endregion
122
+ //#region src/lib/queries/expandListItemsWithChildren.ts
123
+ /**
124
+ * Expands a list of blocks to include list item children. For each list item in
125
+ * the input, adds all its children (items with bigger indent). Non-list blocks
126
+ * are kept as-is. Requires id to be set on the blocks.
127
+ *
128
+ * @returns Array of block entries with list items expanded to include their
129
+ * children
130
+ */
131
+ const expandListItemsWithChildren = (editor, entries) => {
132
+ const expandedEntries = [];
133
+ const processedIds = /* @__PURE__ */ new Set();
134
+ entries.forEach((entry) => {
135
+ const [node] = entry;
136
+ if (processedIds.has(node.id)) return;
137
+ expandedEntries.push(entry);
138
+ processedIds.add(node.id);
139
+ if (isDefined(node[KEYS.listType]) && isDefined(node[KEYS.indent])) getListChildren(editor, entry).forEach((childEntry) => {
140
+ if (!processedIds.has(childEntry[0].id)) {
141
+ expandedEntries.push(childEntry);
142
+ processedIds.add(childEntry[0].id);
143
+ }
144
+ });
145
+ });
146
+ return expandedEntries;
147
+ };
148
+
149
+ //#endregion
150
+ //#region src/lib/queries/getListAbove.ts
151
+ const getListAbove = (editor, options) => editor.api.above({
152
+ ...options,
153
+ match: (node) => isDefined(node[KEYS.listType])
154
+ });
155
+
156
+ //#endregion
157
+ //#region src/lib/queries/getSiblingList.ts
158
+ /**
159
+ * Get the next sibling indent list node. Default query: the sibling node should
160
+ * have the same listStyleType.
161
+ */
162
+ const getSiblingList = (_editor, [node, path], { breakOnEqIndentNeqListStyleType = true, breakOnListRestart = false, breakOnLowerIndent = true, breakQuery, eqIndent = true, getNextEntry, getPreviousEntry, query }) => {
163
+ if (!getPreviousEntry && !getNextEntry) return;
164
+ const getSiblingEntry = getNextEntry ?? getPreviousEntry;
165
+ let nextEntry = getSiblingEntry([node, path]);
166
+ while (true) {
167
+ if (!nextEntry) return;
168
+ const [nextNode, nextPath] = nextEntry;
169
+ const indent = node[KEYS.indent];
170
+ const nextIndent = nextNode[KEYS.indent];
171
+ if (breakQuery?.(nextNode, node)) return;
172
+ if (!isDefined(nextIndent)) return;
173
+ if (breakOnListRestart) {
174
+ if (getPreviousEntry && node[KEYS.listRestart]) return;
175
+ if (getNextEntry && nextNode[KEYS.listRestart]) return;
176
+ }
177
+ if (breakOnLowerIndent && nextIndent < indent) return;
178
+ if (breakOnEqIndentNeqListStyleType && nextIndent === indent && nextNode[KEYS.listType] !== node[KEYS.listType]) return;
179
+ let valid = !query || query(nextNode, node);
180
+ if (valid) {
181
+ valid = !eqIndent || nextIndent === indent;
182
+ if (valid) return [nextNode, nextPath];
183
+ }
184
+ nextEntry = getSiblingEntry(nextEntry);
185
+ }
186
+ };
187
+
188
+ //#endregion
189
+ //#region src/lib/queries/getNextList.ts
190
+ /** Get the next indent list. */
191
+ const getNextList = (editor, entry, options) => getSiblingList(editor, entry, {
192
+ getNextEntry: ([, currPath]) => {
193
+ const nextPath = PathApi.next(currPath);
194
+ const nextNode = NodeApi.get(editor, nextPath);
195
+ if (!nextNode) return;
196
+ return [nextNode, nextPath];
197
+ },
198
+ ...options,
199
+ getPreviousEntry: void 0
200
+ });
201
+
202
+ //#endregion
203
+ //#region src/lib/queries/getPreviousList.ts
204
+ /** Get the previous indent list node. */
205
+ const getPreviousList = (editor, entry, options) => getSiblingList(editor, entry, {
206
+ getPreviousEntry: ([, currPath]) => {
207
+ const prevPath = PathApi.previous(currPath);
208
+ if (!prevPath) return;
209
+ const prevNode = NodeApi.get(editor, prevPath);
210
+ if (!prevNode) return;
211
+ return [prevNode, prevPath];
212
+ },
213
+ ...options,
214
+ getNextEntry: void 0
215
+ });
216
+
217
+ //#endregion
218
+ //#region src/lib/queries/getListSiblings.ts
219
+ const getListSiblings = (editor, entry, { current = true, next = true, previous = true, ...options } = {}) => {
220
+ const siblings = [];
221
+ const node = entry[0];
222
+ if (!node[KEYS.listType] && !Object.hasOwn(node, KEYS.listChecked)) return siblings;
223
+ let iterEntry = entry;
224
+ if (previous) while (true) {
225
+ const prevEntry = getPreviousList(editor, iterEntry, options);
226
+ if (!prevEntry) break;
227
+ siblings.push(prevEntry);
228
+ iterEntry = prevEntry;
229
+ }
230
+ if (current) siblings.push(entry);
231
+ if (next) {
232
+ iterEntry = entry;
233
+ while (true) {
234
+ const nextEntry = getNextList(editor, iterEntry, options);
235
+ if (!nextEntry) break;
236
+ siblings.push(nextEntry);
237
+ iterEntry = nextEntry;
238
+ }
239
+ }
240
+ return siblings;
241
+ };
242
+
243
+ //#endregion
244
+ //#region src/lib/queries/getSiblingListStyleType.ts
245
+ /**
246
+ * Get the first sibling list style type at the given indent. If none, return
247
+ * the entry list style type.
248
+ */
249
+ const getSiblingListStyleType = (editor, { entry, indent, ...options }) => {
250
+ const siblings = getListSiblings(editor, [{
251
+ ...entry[0],
252
+ indent
253
+ }, entry[1]], {
254
+ breakOnEqIndentNeqListStyleType: false,
255
+ current: false,
256
+ eqIndent: true,
257
+ ...options
258
+ });
259
+ return siblings.length > 0 ? siblings[0][0][KEYS.listType] : entry[0][KEYS.listType];
260
+ };
261
+
262
+ //#endregion
263
+ //#region src/lib/queries/isOrderedList.ts
264
+ function isOrderedList(element) {
265
+ return !!element.listStyleType && !ULIST_STYLE_TYPES.includes(element.listStyleType);
266
+ }
267
+
268
+ //#endregion
269
+ //#region src/lib/queries/someList.ts
270
+ const someList = (editor, type) => !!editor.selection && editor.api.some({ match: (n) => {
271
+ if (Object.hasOwn(n, KEYS.listChecked)) return false;
272
+ const list = n[KEYS.listType];
273
+ return Array.isArray(type) ? type.includes(list) : list === type;
274
+ } });
275
+
276
+ //#endregion
277
+ //#region src/lib/queries/someTodoList.ts
278
+ const someTodoList = (editor) => editor.api.some({
279
+ at: editor.selection,
280
+ match: (n) => {
281
+ const list = n[KEYS.listType];
282
+ const isHasProperty = Object.hasOwn(n, KEYS.listChecked);
283
+ return n.type === "p" && isHasProperty && list === KEYS.listTodo;
284
+ }
285
+ });
286
+
287
+ //#endregion
288
+ //#region src/lib/normalizers/normalizeListNotIndented.ts
289
+ /** Unset listStyle, listStart if KEYS.indent is not defined. */
290
+ const normalizeListNotIndented = (editor, [node, path]) => {
291
+ if (!isDefined(node[KEYS.indent]) && (node[KEYS.listType] || node[KEYS.listStart])) {
292
+ editor.tf.unsetNodes([KEYS.listType, KEYS.listStart], { at: path });
293
+ return true;
294
+ }
295
+ };
296
+
297
+ //#endregion
298
+ //#region src/lib/normalizers/normalizeListStart.ts
299
+ const getListExpectedListStart = (entry, prevEntry) => {
300
+ const [node] = entry;
301
+ const [prevNode] = prevEntry ?? [null];
302
+ const restart = node[KEYS.listRestart] ?? null;
303
+ const restartPolite = node[KEYS.listRestartPolite] ?? null;
304
+ if (restart) return restart;
305
+ if (restartPolite && !prevNode) return restartPolite;
306
+ if (prevNode) return (prevNode[KEYS.listStart] ?? 1) + 1;
307
+ return 1;
308
+ };
309
+ const normalizeListStart = (editor, entry, options) => editor.tf.withoutNormalizing(() => {
310
+ const [node, path] = entry;
311
+ const listStyleType = node[KEYS.listType];
312
+ const listStart = node[KEYS.listStart];
313
+ if (!listStyleType) return;
314
+ const expectedListStart = getListExpectedListStart(entry, getPreviousList(editor, entry, options));
315
+ if (isDefined(listStart) && expectedListStart === 1) {
316
+ editor.tf.unsetNodes(KEYS.listStart, { at: path });
317
+ return true;
318
+ }
319
+ if (listStart !== expectedListStart && expectedListStart > 1) {
320
+ editor.tf.setNodes({ [KEYS.listStart]: expectedListStart }, { at: path });
321
+ return true;
322
+ }
323
+ return false;
324
+ });
325
+
326
+ //#endregion
327
+ //#region src/lib/normalizers/withInsertBreakList.ts
328
+ const withInsertBreakList = ({ editor, tf: { insertBreak } }) => ({ transforms: { insertBreak() {
329
+ const nodeEntry = editor.api.above();
330
+ if (!nodeEntry) return insertBreak();
331
+ const [node, path] = nodeEntry;
332
+ if (!isDefined(node[KEYS.listType]) || node[KEYS.listType] !== KEYS.listTodo || editor.api.isExpanded() || !editor.api.isEnd(editor.selection?.focus, path)) return insertBreak();
333
+ editor.tf.withoutNormalizing(() => {
334
+ insertBreak();
335
+ const newEntry = editor.api.above();
336
+ if (newEntry) editor.tf.setNodes({ checked: false }, { at: newEntry[1] });
337
+ });
338
+ } } });
339
+
340
+ //#endregion
341
+ //#region src/lib/transforms/indentList.ts
342
+ /** Increase the indentation of the selected blocks. */
343
+ const indentList = (editor, { listStyleType = ListStyleType.Disc, ...options } = {}) => {
344
+ setIndent(editor, {
345
+ offset: 1,
346
+ setNodesProps: () => ({ [KEYS.listType]: listStyleType }),
347
+ ...options
348
+ });
349
+ };
350
+ const indentTodo = (editor, { listStyleType = ListStyleType.Disc, ...options } = {}) => {
351
+ setIndent(editor, {
352
+ offset: 1,
353
+ setNodesProps: () => ({
354
+ [KEYS.listChecked]: false,
355
+ [KEYS.listType]: listStyleType
356
+ }),
357
+ ...options
358
+ });
359
+ };
360
+
361
+ //#endregion
362
+ //#region src/lib/transforms/outdentList.ts
363
+ /** Decrease the indentation of the selected blocks. */
364
+ const outdentList = (editor, options = {}) => {
365
+ setIndent(editor, {
366
+ offset: -1,
367
+ unsetNodesProps: [KEYS.listType, KEYS.listChecked],
368
+ ...options
369
+ });
370
+ };
371
+
372
+ //#endregion
373
+ //#region src/lib/transforms/setListNode.ts
374
+ const setListNode = (editor, { at, indent = 0, listStyleType = ListStyleType.Disc }) => {
375
+ const newIndent = indent || indent + 1;
376
+ editor.tf.setNodes({
377
+ [KEYS.indent]: newIndent,
378
+ [KEYS.listType]: listStyleType
379
+ }, { at });
380
+ };
381
+ const setIndentTodoNode = (editor, { at, indent = 0, listStyleType = KEYS.listTodo }) => {
382
+ const newIndent = indent || indent + 1;
383
+ editor.tf.setNodes({
384
+ [KEYS.indent]: newIndent,
385
+ [KEYS.listChecked]: false,
386
+ [KEYS.listType]: listStyleType
387
+ }, { at });
388
+ };
389
+
390
+ //#endregion
391
+ //#region src/lib/transforms/setListNodes.ts
392
+ /**
393
+ * Set indent list to the given entries. Add indent if listStyleType was not
394
+ * defined.
395
+ */
396
+ const setListNodes = (editor, entries, { listStyleType = ListStyleType.Disc }) => {
397
+ editor.tf.withoutNormalizing(() => {
398
+ entries.forEach((entry) => {
399
+ const [node, path] = entry;
400
+ let indent = node[KEYS.indent] ?? 0;
401
+ indent = node[KEYS.listType] || Object.hasOwn(node, KEYS.listChecked) ? indent : indent + 1;
402
+ if (listStyleType === "todo") {
403
+ editor.tf.unsetNodes(KEYS.listType, { at: path });
404
+ setIndentTodoNode(editor, {
405
+ at: path,
406
+ indent,
407
+ listStyleType
408
+ });
409
+ return;
410
+ }
411
+ editor.tf.unsetNodes(KEYS.listChecked, { at: path });
412
+ setListNode(editor, {
413
+ at: path,
414
+ indent,
415
+ listStyleType
416
+ });
417
+ });
418
+ });
419
+ };
420
+
421
+ //#endregion
422
+ //#region src/lib/transforms/setListSiblingNodes.ts
423
+ /** Set indent list to entry + siblings. */
424
+ const setListSiblingNodes = (editor, entry, { getSiblingListOptions, listStyleType = ListStyleType.Disc }) => {
425
+ editor.tf.withoutNormalizing(() => {
426
+ getListSiblings(editor, entry, getSiblingListOptions).forEach(([node, path]) => {
427
+ if (listStyleType === KEYS.listTodo) {
428
+ editor.tf.unsetNodes(KEYS.listType, { at: path });
429
+ setIndentTodoNode(editor, {
430
+ at: path,
431
+ indent: node[KEYS.indent],
432
+ listStyleType
433
+ });
434
+ } else {
435
+ editor.tf.unsetNodes(KEYS.listChecked, { at: path });
436
+ setListNode(editor, {
437
+ at: path,
438
+ indent: node[KEYS.indent],
439
+ listStyleType
440
+ });
441
+ }
442
+ });
443
+ });
444
+ };
445
+
446
+ //#endregion
447
+ //#region src/lib/transforms/toggleListSet.ts
448
+ /** Set indent list if not set. */
449
+ const toggleListSet = (editor, [node, _path], { listStyleType = ListStyleType.Disc, ...options }) => {
450
+ if (Object.hasOwn(node, KEYS.listChecked) || node[KEYS.listType]) return;
451
+ if (listStyleType === "todo") indentTodo(editor, {
452
+ listStyleType,
453
+ ...options
454
+ });
455
+ else indentList(editor, {
456
+ listStyleType,
457
+ ...options
458
+ });
459
+ return true;
460
+ };
461
+
462
+ //#endregion
463
+ //#region src/lib/transforms/toggleListUnset.ts
464
+ /** Unset list style type if already set. */
465
+ const toggleListUnset = (editor, [node, path], { listStyleType = ListStyleType.Disc }) => {
466
+ if (listStyleType === KEYS.listTodo && Object.hasOwn(node, KEYS.listChecked)) {
467
+ editor.tf.unsetNodes(KEYS.listChecked, { at: path });
468
+ outdentList(editor, { listStyleType });
469
+ return true;
470
+ }
471
+ if (listStyleType === node[KEYS.listType]) {
472
+ editor.tf.unsetNodes([KEYS.listType], { at: path });
473
+ outdentList(editor, { listStyleType });
474
+ return true;
475
+ }
476
+ };
477
+
478
+ //#endregion
479
+ //#region src/lib/transforms/toggleList.ts
480
+ /** Toggle indent list. */
481
+ const toggleList = (editor, options, getSiblingListOptions) => {
482
+ const { listRestart, listRestartPolite, listStyleType } = options;
483
+ /**
484
+ * True - One or more blocks were converted to lists or changed such that they
485
+ * remain lists.
486
+ *
487
+ * False - One or more list blocks were unset.
488
+ *
489
+ * Null - No action was taken.
490
+ */
491
+ const setList = (() => {
492
+ const { getSiblingListOptions: _getSiblingListOptions } = editor.getOptions(BaseListPlugin);
493
+ if (editor.api.isCollapsed()) {
494
+ const entry = editor.api.block();
495
+ if (!entry) return null;
496
+ if (toggleListSet(editor, entry, options)) return true;
497
+ if (toggleListUnset(editor, entry, { listStyleType })) return false;
498
+ setListSiblingNodes(editor, entry, {
499
+ getSiblingListOptions: {
500
+ ..._getSiblingListOptions,
501
+ ...getSiblingListOptions
502
+ },
503
+ listStyleType
504
+ });
505
+ return true;
506
+ }
507
+ if (editor.api.isExpanded()) {
508
+ const match = getInjectMatch(editor, editor.getPlugin({ key: KEYS.list }));
509
+ const entries = [...editor.api.nodes({
510
+ block: true,
511
+ match
512
+ })];
513
+ if (areEqListStyleType(editor, entries, { listStyleType })) {
514
+ editor.tf.withoutNormalizing(() => {
515
+ entries.forEach((entry) => {
516
+ const [node, path] = entry;
517
+ const indent = node[KEYS.indent];
518
+ editor.tf.unsetNodes(KEYS.listType, { at: path });
519
+ if (indent > 1) editor.tf.setNodes({ [KEYS.indent]: indent - 1 }, { at: path });
520
+ else editor.tf.unsetNodes([KEYS.indent, KEYS.listChecked], { at: path });
521
+ });
522
+ });
523
+ return false;
524
+ }
525
+ setListNodes(editor, entries, { listStyleType });
526
+ return true;
527
+ }
528
+ return null;
529
+ })();
530
+ const restartValue = listRestart || listRestartPolite;
531
+ const isRestart = !!listRestart;
532
+ if (setList && restartValue) {
533
+ const entry = getListAbove(editor, { at: editor.api.start(editor.selection) });
534
+ if (!entry) return;
535
+ const isFirst = !getPreviousList(editor, entry);
536
+ /**
537
+ * Only apply listRestartPolite if this is the first item and restartValue >
538
+ * 1.
539
+ */
540
+ if (!isRestart && (!isFirst || restartValue <= 0)) return;
541
+ if (isRestart && restartValue === 1 && isFirst) return;
542
+ const prop = isRestart ? KEYS.listRestart : KEYS.listRestartPolite;
543
+ editor.tf.setNodes({ [prop]: restartValue }, { at: entry[1] });
544
+ }
545
+ };
546
+
547
+ //#endregion
548
+ //#region src/lib/transforms/toggleListByPath.ts
549
+ const toggleListByPath = (editor, [node, path], listStyleType) => {
550
+ editor.tf.setNodes({
551
+ [KEYS.indent]: node.indent ?? 1,
552
+ [KEYS.listChecked]: false,
553
+ [KEYS.listType]: listStyleType,
554
+ type: KEYS.p
555
+ }, { at: path });
556
+ };
557
+ const toggleListByPathUnSet = (editor, [, path]) => editor.tf.unsetNodes([
558
+ KEYS.listType,
559
+ KEYS.indent,
560
+ KEYS.listChecked
561
+ ], { at: path });
562
+
563
+ //#endregion
564
+ //#region src/lib/withNormalizeList.ts
565
+ const withNormalizeList = ({ editor, getOptions, tf: { normalizeNode } }) => ({ transforms: { normalizeNode([node, path]) {
566
+ if (editor.tf.withoutNormalizing(() => {
567
+ if (normalizeListNotIndented(editor, [node, path])) return true;
568
+ if (normalizeListStart(editor, [node, path], getOptions().getSiblingListOptions)) return true;
569
+ })) return;
570
+ return normalizeNode([node, path]);
571
+ } } });
572
+
573
+ //#endregion
574
+ //#region src/lib/withList.ts
575
+ const withList = (ctx) => {
576
+ const { editor, getOptions, tf: { apply, resetBlock } } = ctx;
577
+ return { transforms: {
578
+ resetBlock(options) {
579
+ if (editor.api.block(options)?.[0]?.[KEYS.listType]) {
580
+ outdentList(editor);
581
+ return;
582
+ }
583
+ return resetBlock(options);
584
+ },
585
+ ...withNormalizeList(ctx).transforms,
586
+ ...withInsertBreakList(ctx).transforms,
587
+ apply(operation) {
588
+ const { getSiblingListOptions } = getOptions();
589
+ /**
590
+ * If there is a previous indent list, the inserted indent list style
591
+ * type should be the same. Only for lower-roman and upper-roman as it
592
+ * overlaps with lower-alpha and upper-alpha.
593
+ */
594
+ if (operation.type === "insert_node") {
595
+ const listStyleType = operation.node[KEYS.listType];
596
+ if (listStyleType && ["lower-roman", "upper-roman"].includes(listStyleType)) {
597
+ const prevNodeEntry = getPreviousList(editor, [operation.node, operation.path], {
598
+ breakOnEqIndentNeqListStyleType: false,
599
+ eqIndent: false,
600
+ ...getSiblingListOptions
601
+ });
602
+ if (prevNodeEntry) {
603
+ const prevListStyleType = prevNodeEntry[0][KEYS.listType];
604
+ if (prevListStyleType === ListStyleType.LowerAlpha && listStyleType === ListStyleType.LowerRoman) operation.node[KEYS.listType] = ListStyleType.LowerAlpha;
605
+ else if (prevListStyleType === ListStyleType.UpperAlpha && listStyleType === ListStyleType.UpperRoman) operation.node[KEYS.listType] = ListStyleType.UpperAlpha;
606
+ }
607
+ }
608
+ }
609
+ /**
610
+ * When inserting a line break, remove listRestart and listRestartPolite
611
+ * from the new list item.
612
+ */
613
+ if (operation.type === "split_node" && operation.properties[KEYS.listType]) {
614
+ delete operation.properties[KEYS.listRestart];
615
+ delete operation.properties[KEYS.listRestartPolite];
616
+ }
617
+ apply(operation);
618
+ const affectedPaths = [];
619
+ switch (operation.type) {
620
+ case "insert_node":
621
+ case "remove_node":
622
+ case "set_node":
623
+ affectedPaths.push(operation.path);
624
+ break;
625
+ case "merge_node":
626
+ affectedPaths.push(PathApi.previous(operation.path));
627
+ break;
628
+ case "move_node":
629
+ affectedPaths.push(operation.path, operation.newPath);
630
+ break;
631
+ case "split_node":
632
+ affectedPaths.push(operation.path, PathApi.next(operation.path));
633
+ break;
634
+ }
635
+ const isListItem = (node) => KEYS.listType in node;
636
+ affectedPaths.forEach((affectedPath) => {
637
+ let entry = editor.api.node(affectedPath);
638
+ if (!entry) return;
639
+ /**
640
+ * Even if the affected node isn't a list item, the subsequent node
641
+ * might be, in which case we want to normalize that node instead.
642
+ */
643
+ if (!isListItem(entry[0])) entry = editor.api.node(PathApi.next(affectedPath));
644
+ while (entry && isListItem(entry[0])) {
645
+ /**
646
+ * Break early since the subsequent list items will already have
647
+ * been normalized by the `apply` that modified the current node.
648
+ */
649
+ if (normalizeListStart(editor, entry, getSiblingListOptions)) break;
650
+ entry = getNextList(editor, entry, {
651
+ ...getSiblingListOptions,
652
+ breakOnEqIndentNeqListStyleType: false,
653
+ breakOnLowerIndent: false,
654
+ eqIndent: false
655
+ });
656
+ }
657
+ });
658
+ }
659
+ } };
660
+ };
661
+
662
+ //#endregion
663
+ //#region src/lib/BaseListPlugin.tsx
664
+ const BaseListPlugin = createTSlatePlugin({
665
+ key: KEYS.list,
666
+ inject: {
667
+ plugins: { [KEYS.html]: { parser: { transformData: ({ data }) => {
668
+ const { body } = new DOMParser().parseFromString(data, "text/html");
669
+ const lisWithNestedLists = [];
670
+ traverseHtmlElements(body, (element) => {
671
+ if (element.tagName === "LI") {
672
+ const nestedLists = [];
673
+ Array.from(element.children).forEach((child) => {
674
+ if (child.tagName === "UL" || child.tagName === "OL") nestedLists.push(child);
675
+ });
676
+ if (nestedLists.length > 0) lisWithNestedLists.push({
677
+ li: element,
678
+ nestedLists
679
+ });
680
+ }
681
+ return true;
682
+ });
683
+ lisWithNestedLists.forEach(({ li, nestedLists }) => {
684
+ nestedLists.forEach((nestedList) => {
685
+ nestedList.remove();
686
+ if (li.parentNode) li.parentNode.insertBefore(nestedList, li.nextSibling);
687
+ });
688
+ });
689
+ traverseHtmlElements(body, (element) => {
690
+ if (element.tagName === "LI") {
691
+ const htmlElement = element;
692
+ const { childNodes } = element;
693
+ const liChildren = [];
694
+ childNodes.forEach((child) => {
695
+ if (child.nodeType === Node.ELEMENT_NODE) {
696
+ const childElement = child;
697
+ if (isHtmlBlockElement(childElement)) {
698
+ liChildren.push(...childElement.childNodes);
699
+ return;
700
+ }
701
+ }
702
+ liChildren.push(child);
703
+ });
704
+ element.replaceChildren(...liChildren);
705
+ const ariaLevel = element.getAttribute("aria-level");
706
+ if (ariaLevel) htmlElement.dataset.indent = ariaLevel;
707
+ else {
708
+ let indent = 0;
709
+ let parent = element.parentElement;
710
+ while (parent && parent !== body) {
711
+ if (parent.tagName === "UL" || parent.tagName === "OL") indent++;
712
+ parent = parent.parentElement;
713
+ }
714
+ if (indent > 0) htmlElement.dataset.indent = String(indent);
715
+ }
716
+ const listStyleType = htmlElement.style.listStyleType;
717
+ if (listStyleType) htmlElement.dataset.listStyleType = listStyleType;
718
+ else {
719
+ const listParent = element.closest("ul, ol");
720
+ if (listParent) {
721
+ const parentListStyleType = listParent.style.listStyleType;
722
+ if (parentListStyleType) htmlElement.dataset.listStyleType = parentListStyleType;
723
+ else if (listParent.tagName === "UL") htmlElement.dataset.listStyleType = "disc";
724
+ else if (listParent.tagName === "OL") htmlElement.dataset.listStyleType = "decimal";
725
+ }
726
+ }
727
+ return false;
728
+ }
729
+ return true;
730
+ });
731
+ return postCleanHtml(body.innerHTML);
732
+ } } } },
733
+ targetPlugins: [KEYS.p]
734
+ },
735
+ options: { getListStyleType: (element) => element.style.listStyleType },
736
+ parsers: { html: { deserializer: {
737
+ isElement: true,
738
+ rules: [{ validNodeName: "LI" }],
739
+ parse: ({ editor, element, getOptions }) => {
740
+ const dataIndent = element.dataset.indent;
741
+ const ariaLevel = element.getAttribute("aria-level");
742
+ const indent = dataIndent ? Number(dataIndent) : Number(ariaLevel);
743
+ const listStyleType = element.dataset.listStyleType || getOptions().getListStyleType?.(element);
744
+ return {
745
+ indent: indent || void 0,
746
+ listStyleType: listStyleType || void 0,
747
+ type: editor.getType(KEYS.p)
748
+ };
749
+ }
750
+ } } },
751
+ render: { belowNodes: (props) => {
752
+ if (!props.element.listStyleType) return;
753
+ return (props$1) => /* @__PURE__ */ React.createElement(List, props$1);
754
+ } },
755
+ rules: {
756
+ break: {
757
+ empty: "reset",
758
+ splitReset: false
759
+ },
760
+ delete: { start: "reset" },
761
+ merge: { removeEmpty: false },
762
+ match: ({ node }) => isDefined(node[KEYS.listType])
763
+ }
764
+ }).overrideEditor(withList);
765
+ function List(props) {
766
+ const $ = c(9);
767
+ const { listStart, listStyleType } = props.element;
768
+ const List$1 = isOrderedList(props.element) ? "ol" : "ul";
769
+ let t0;
770
+ if ($[0] !== listStyleType) {
771
+ t0 = {
772
+ listStyleType,
773
+ margin: 0,
774
+ padding: 0,
775
+ position: "relative"
776
+ };
777
+ $[0] = listStyleType;
778
+ $[1] = t0;
779
+ } else t0 = $[1];
780
+ let t1;
781
+ if ($[2] !== props.children) {
782
+ t1 = /* @__PURE__ */ React.createElement("li", null, props.children);
783
+ $[2] = props.children;
784
+ $[3] = t1;
785
+ } else t1 = $[3];
786
+ let t2;
787
+ if ($[4] !== List$1 || $[5] !== listStart || $[6] !== t0 || $[7] !== t1) {
788
+ t2 = /* @__PURE__ */ React.createElement(List$1, {
789
+ style: t0,
790
+ start: listStart
791
+ }, t1);
792
+ $[4] = List$1;
793
+ $[5] = listStart;
794
+ $[6] = t0;
795
+ $[7] = t1;
796
+ $[8] = t2;
797
+ } else t2 = $[8];
798
+ return t2;
799
+ }
800
+
801
+ //#endregion
802
+ export { getListChildren as A, getSiblingListStyleType as C, getSiblingList as D, getNextList as E, ListStyleType as M, ULIST_STYLE_TYPES as N, getListAbove as O, isOrderedList as S, getPreviousList as T, getListExpectedListStart as _, toggleListByPathUnSet as a, someTodoList as b, toggleListSet as c, setIndentTodoNode as d, setListNode as f, withInsertBreakList as g, indentTodo as h, toggleListByPath as i, areEqListStyleType as j, expandListItemsWithChildren as k, setListSiblingNodes as l, indentList as m, withList as n, toggleList as o, outdentList as p, withNormalizeList as r, toggleListUnset as s, BaseListPlugin as t, setListNodes as u, normalizeListStart as v, getListSiblings as w, someList as x, normalizeListNotIndented as y };
803
+ //# sourceMappingURL=src-Dvsp2AeZ.js.map