@tiptap/extension-list 3.6.6 → 3.7.0

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.
@@ -50,6 +50,25 @@ var BulletList = import_core.Node.create({
50
50
  renderHTML({ HTMLAttributes }) {
51
51
  return ["ul", (0, import_core.mergeAttributes)(this.options.HTMLAttributes, HTMLAttributes), 0];
52
52
  },
53
+ markdownTokenName: "list",
54
+ parseMarkdown: (token, helpers) => {
55
+ if (token.type !== "list" || token.ordered) {
56
+ return [];
57
+ }
58
+ return {
59
+ type: "bulletList",
60
+ content: token.items ? helpers.parseChildren(token.items) : []
61
+ };
62
+ },
63
+ renderMarkdown: (node, h) => {
64
+ if (!node.content) {
65
+ return "";
66
+ }
67
+ return h.renderChildren(node.content, "\n");
68
+ },
69
+ markdownOptions: {
70
+ indentsContent: true
71
+ },
53
72
  addCommands() {
54
73
  return {
55
74
  toggleBulletList: () => ({ commands, chain }) => {
@@ -109,6 +128,65 @@ var ListItem = import_core2.Node.create({
109
128
  renderHTML({ HTMLAttributes }) {
110
129
  return ["li", (0, import_core2.mergeAttributes)(this.options.HTMLAttributes, HTMLAttributes), 0];
111
130
  },
131
+ markdownTokenName: "list_item",
132
+ parseMarkdown: (token, helpers) => {
133
+ if (token.type !== "list_item") {
134
+ return [];
135
+ }
136
+ let content = [];
137
+ if (token.tokens && token.tokens.length > 0) {
138
+ const hasParagraphTokens = token.tokens.some((t) => t.type === "paragraph");
139
+ if (hasParagraphTokens) {
140
+ content = helpers.parseChildren(token.tokens);
141
+ } else {
142
+ const firstToken = token.tokens[0];
143
+ if (firstToken && firstToken.type === "text" && firstToken.tokens && firstToken.tokens.length > 0) {
144
+ const inlineContent = helpers.parseInline(firstToken.tokens);
145
+ content = [
146
+ {
147
+ type: "paragraph",
148
+ content: inlineContent
149
+ }
150
+ ];
151
+ if (token.tokens.length > 1) {
152
+ const remainingTokens = token.tokens.slice(1);
153
+ const additionalContent = helpers.parseChildren(remainingTokens);
154
+ content.push(...additionalContent);
155
+ }
156
+ } else {
157
+ content = helpers.parseChildren(token.tokens);
158
+ }
159
+ }
160
+ }
161
+ if (content.length === 0) {
162
+ content = [
163
+ {
164
+ type: "paragraph",
165
+ content: []
166
+ }
167
+ ];
168
+ }
169
+ return {
170
+ type: "listItem",
171
+ content
172
+ };
173
+ },
174
+ renderMarkdown: (node, h, ctx) => {
175
+ return (0, import_core2.renderNestedMarkdownContent)(
176
+ node,
177
+ h,
178
+ (context) => {
179
+ if (context.parentType === "bulletList") {
180
+ return "- ";
181
+ }
182
+ if (context.parentType === "orderedList") {
183
+ return `${context.index + 1}. `;
184
+ }
185
+ return "- ";
186
+ },
187
+ ctx
188
+ );
189
+ },
112
190
  addKeyboardShortcuts() {
113
191
  return {
114
192
  Enter: () => this.editor.commands.splitListItem(this.name),
@@ -396,6 +474,138 @@ var ListKeymap = import_core8.Extension.create({
396
474
 
397
475
  // src/ordered-list/ordered-list.ts
398
476
  var import_core9 = require("@tiptap/core");
477
+
478
+ // src/ordered-list/utils.ts
479
+ var ORDERED_LIST_ITEM_REGEX = /^(\s*)(\d+)\.\s+(.*)$/;
480
+ var INDENTED_LINE_REGEX = /^\s/;
481
+ function collectOrderedListItems(lines) {
482
+ const listItems = [];
483
+ let currentLineIndex = 0;
484
+ let consumed = 0;
485
+ while (currentLineIndex < lines.length) {
486
+ const line = lines[currentLineIndex];
487
+ const match = line.match(ORDERED_LIST_ITEM_REGEX);
488
+ if (!match) {
489
+ break;
490
+ }
491
+ const [, indent, number, content] = match;
492
+ const indentLevel = indent.length;
493
+ let itemContent = content;
494
+ let nextLineIndex = currentLineIndex + 1;
495
+ const itemLines = [line];
496
+ while (nextLineIndex < lines.length) {
497
+ const nextLine = lines[nextLineIndex];
498
+ const nextMatch = nextLine.match(ORDERED_LIST_ITEM_REGEX);
499
+ if (nextMatch) {
500
+ break;
501
+ }
502
+ if (nextLine.trim() === "") {
503
+ itemLines.push(nextLine);
504
+ itemContent += "\n";
505
+ nextLineIndex += 1;
506
+ } else if (nextLine.match(INDENTED_LINE_REGEX)) {
507
+ itemLines.push(nextLine);
508
+ itemContent += `
509
+ ${nextLine.slice(indentLevel + 2)}`;
510
+ nextLineIndex += 1;
511
+ } else {
512
+ break;
513
+ }
514
+ }
515
+ listItems.push({
516
+ indent: indentLevel,
517
+ number: parseInt(number, 10),
518
+ content: itemContent.trim(),
519
+ raw: itemLines.join("\n")
520
+ });
521
+ consumed = nextLineIndex;
522
+ currentLineIndex = nextLineIndex;
523
+ }
524
+ return [listItems, consumed];
525
+ }
526
+ function buildNestedStructure(items, baseIndent, lexer) {
527
+ var _a;
528
+ const result = [];
529
+ let currentIndex = 0;
530
+ while (currentIndex < items.length) {
531
+ const item = items[currentIndex];
532
+ if (item.indent === baseIndent) {
533
+ const contentLines = item.content.split("\n");
534
+ const mainText = ((_a = contentLines[0]) == null ? void 0 : _a.trim()) || "";
535
+ const tokens = [];
536
+ if (mainText) {
537
+ tokens.push({
538
+ type: "paragraph",
539
+ raw: mainText,
540
+ tokens: lexer.inlineTokens(mainText)
541
+ });
542
+ }
543
+ const additionalContent = contentLines.slice(1).join("\n").trim();
544
+ if (additionalContent) {
545
+ const blockTokens = lexer.blockTokens(additionalContent);
546
+ tokens.push(...blockTokens);
547
+ }
548
+ let lookAheadIndex = currentIndex + 1;
549
+ const nestedItems = [];
550
+ while (lookAheadIndex < items.length && items[lookAheadIndex].indent > baseIndent) {
551
+ nestedItems.push(items[lookAheadIndex]);
552
+ lookAheadIndex += 1;
553
+ }
554
+ if (nestedItems.length > 0) {
555
+ const nextIndent = Math.min(...nestedItems.map((nestedItem) => nestedItem.indent));
556
+ const nestedListItems = buildNestedStructure(nestedItems, nextIndent, lexer);
557
+ tokens.push({
558
+ type: "list",
559
+ ordered: true,
560
+ start: nestedItems[0].number,
561
+ items: nestedListItems,
562
+ raw: nestedItems.map((nestedItem) => nestedItem.raw).join("\n")
563
+ });
564
+ }
565
+ result.push({
566
+ type: "list_item",
567
+ raw: item.raw,
568
+ tokens
569
+ });
570
+ currentIndex = lookAheadIndex;
571
+ } else {
572
+ currentIndex += 1;
573
+ }
574
+ }
575
+ return result;
576
+ }
577
+ function parseListItems(items, helpers) {
578
+ return items.map((item) => {
579
+ if (item.type !== "list_item") {
580
+ return helpers.parseChildren([item])[0];
581
+ }
582
+ const content = [];
583
+ if (item.tokens && item.tokens.length > 0) {
584
+ item.tokens.forEach((itemToken) => {
585
+ if (itemToken.type === "paragraph" || itemToken.type === "list" || itemToken.type === "blockquote" || itemToken.type === "code") {
586
+ content.push(...helpers.parseChildren([itemToken]));
587
+ } else if (itemToken.type === "text" && itemToken.tokens) {
588
+ const inlineContent = helpers.parseChildren([itemToken]);
589
+ content.push({
590
+ type: "paragraph",
591
+ content: inlineContent
592
+ });
593
+ } else {
594
+ const parsed = helpers.parseChildren([itemToken]);
595
+ if (parsed.length > 0) {
596
+ content.push(...parsed);
597
+ }
598
+ }
599
+ });
600
+ }
601
+ return {
602
+ type: "listItem",
603
+ content
604
+ };
605
+ });
606
+ }
607
+
608
+ // src/ordered-list/ordered-list.ts
399
609
  var ListItemName2 = "listItem";
400
610
  var TextStyleName2 = "textStyle";
401
611
  var orderedListInputRegex = /^(\d+)\.\s$/;
@@ -438,6 +648,63 @@ var OrderedList = import_core9.Node.create({
438
648
  const { start, ...attributesWithoutStart } = HTMLAttributes;
439
649
  return start === 1 ? ["ol", (0, import_core9.mergeAttributes)(this.options.HTMLAttributes, attributesWithoutStart), 0] : ["ol", (0, import_core9.mergeAttributes)(this.options.HTMLAttributes, HTMLAttributes), 0];
440
650
  },
651
+ markdownTokenName: "list",
652
+ parseMarkdown: (token, helpers) => {
653
+ if (token.type !== "list" || !token.ordered) {
654
+ return [];
655
+ }
656
+ const startValue = token.start || 1;
657
+ const content = token.items ? parseListItems(token.items, helpers) : [];
658
+ if (startValue !== 1) {
659
+ return {
660
+ type: "orderedList",
661
+ attrs: { start: startValue },
662
+ content
663
+ };
664
+ }
665
+ return {
666
+ type: "orderedList",
667
+ content
668
+ };
669
+ },
670
+ renderMarkdown: (node, h) => {
671
+ if (!node.content) {
672
+ return "";
673
+ }
674
+ return h.renderChildren(node.content, "\n");
675
+ },
676
+ markdownTokenizer: {
677
+ name: "orderedList",
678
+ level: "block",
679
+ start: (src) => {
680
+ const match = src.match(/^(\s*)(\d+)\.\s+/);
681
+ const index = match == null ? void 0 : match.index;
682
+ return index !== void 0 ? index : -1;
683
+ },
684
+ tokenize: (src, _tokens, lexer) => {
685
+ var _a;
686
+ const lines = src.split("\n");
687
+ const [listItems, consumed] = collectOrderedListItems(lines);
688
+ if (listItems.length === 0) {
689
+ return void 0;
690
+ }
691
+ const items = buildNestedStructure(listItems, 0, lexer);
692
+ if (items.length === 0) {
693
+ return void 0;
694
+ }
695
+ const startValue = ((_a = listItems[0]) == null ? void 0 : _a.number) || 1;
696
+ return {
697
+ type: "list",
698
+ ordered: true,
699
+ start: startValue,
700
+ items,
701
+ raw: lines.slice(0, consumed).join("\n")
702
+ };
703
+ }
704
+ },
705
+ markdownOptions: {
706
+ indentsContent: true
707
+ },
441
708
  addCommands() {
442
709
  return {
443
710
  toggleOrderedList: () => ({ commands, chain }) => {
@@ -535,6 +802,27 @@ var TaskItem = import_core10.Node.create({
535
802
  ["div", 0]
536
803
  ];
537
804
  },
805
+ parseMarkdown: (token, h) => {
806
+ const content = [];
807
+ if (token.tokens && token.tokens.length > 0) {
808
+ content.push(h.createNode("paragraph", {}, h.parseInline(token.tokens)));
809
+ } else if (token.text) {
810
+ content.push(h.createNode("paragraph", {}, [h.createNode("text", { text: token.text })]));
811
+ } else {
812
+ content.push(h.createNode("paragraph", {}, []));
813
+ }
814
+ if (token.nestedTokens && token.nestedTokens.length > 0) {
815
+ const nestedContent = h.parseChildren(token.nestedTokens);
816
+ content.push(...nestedContent);
817
+ }
818
+ return h.createNode("taskItem", { checked: token.checked || false }, content);
819
+ },
820
+ renderMarkdown: (node, h) => {
821
+ var _a;
822
+ const checkedChar = ((_a = node.attrs) == null ? void 0 : _a.checked) ? "x" : " ";
823
+ const prefix = `- [${checkedChar}] `;
824
+ return (0, import_core10.renderNestedMarkdownContent)(node, h, prefix);
825
+ },
538
826
  addKeyboardShortcuts() {
539
827
  const shortcuts = {
540
828
  Enter: () => this.editor.commands.splitListItem(this.name),
@@ -652,6 +940,97 @@ var TaskList = import_core11.Node.create({
652
940
  renderHTML({ HTMLAttributes }) {
653
941
  return ["ul", (0, import_core11.mergeAttributes)(this.options.HTMLAttributes, HTMLAttributes, { "data-type": this.name }), 0];
654
942
  },
943
+ parseMarkdown: (token, h) => {
944
+ return h.createNode("taskList", {}, h.parseChildren(token.items || []));
945
+ },
946
+ renderMarkdown: (node, h) => {
947
+ if (!node.content) {
948
+ return "";
949
+ }
950
+ return h.renderChildren(node.content, "\n");
951
+ },
952
+ markdownTokenizer: {
953
+ name: "taskList",
954
+ level: "block",
955
+ start(src) {
956
+ var _a;
957
+ const index = (_a = src.match(/^\s*[-+*]\s+\[([ xX])\]\s+/)) == null ? void 0 : _a.index;
958
+ return index !== void 0 ? index : -1;
959
+ },
960
+ tokenize(src, tokens, lexer) {
961
+ const parseTaskListContent = (content) => {
962
+ const nestedResult = (0, import_core11.parseIndentedBlocks)(
963
+ content,
964
+ {
965
+ itemPattern: /^(\s*)([-+*])\s+\[([ xX])\]\s+(.*)$/,
966
+ extractItemData: (match) => ({
967
+ indentLevel: match[1].length,
968
+ mainContent: match[4],
969
+ checked: match[3].toLowerCase() === "x"
970
+ }),
971
+ createToken: (data, nestedTokens) => ({
972
+ type: "taskItem",
973
+ raw: "",
974
+ mainContent: data.mainContent,
975
+ indentLevel: data.indentLevel,
976
+ checked: data.checked,
977
+ text: data.mainContent,
978
+ tokens: lexer.inlineTokens(data.mainContent),
979
+ nestedTokens
980
+ }),
981
+ // Allow recursive nesting
982
+ customNestedParser: parseTaskListContent
983
+ },
984
+ lexer
985
+ );
986
+ if (nestedResult) {
987
+ return [
988
+ {
989
+ type: "taskList",
990
+ raw: nestedResult.raw,
991
+ items: nestedResult.items
992
+ }
993
+ ];
994
+ }
995
+ return lexer.blockTokens(content);
996
+ };
997
+ const result = (0, import_core11.parseIndentedBlocks)(
998
+ src,
999
+ {
1000
+ itemPattern: /^(\s*)([-+*])\s+\[([ xX])\]\s+(.*)$/,
1001
+ extractItemData: (match) => ({
1002
+ indentLevel: match[1].length,
1003
+ mainContent: match[4],
1004
+ checked: match[3].toLowerCase() === "x"
1005
+ }),
1006
+ createToken: (data, nestedTokens) => ({
1007
+ type: "taskItem",
1008
+ raw: "",
1009
+ mainContent: data.mainContent,
1010
+ indentLevel: data.indentLevel,
1011
+ checked: data.checked,
1012
+ text: data.mainContent,
1013
+ tokens: lexer.inlineTokens(data.mainContent),
1014
+ nestedTokens
1015
+ }),
1016
+ // Use the recursive parser for nested content
1017
+ customNestedParser: parseTaskListContent
1018
+ },
1019
+ lexer
1020
+ );
1021
+ if (!result) {
1022
+ return void 0;
1023
+ }
1024
+ return {
1025
+ type: "taskList",
1026
+ raw: result.raw,
1027
+ items: result.items
1028
+ };
1029
+ }
1030
+ },
1031
+ markdownOptions: {
1032
+ indentsContent: true
1033
+ },
655
1034
  addCommands() {
656
1035
  return {
657
1036
  toggleTaskList: () => ({ commands }) => {