@thomasjahoda-forks/tiptap-extension-list 3.0.7 → 3.18.0-1

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.
Files changed (41) hide show
  1. package/dist/bullet-list/index.cjs +19 -0
  2. package/dist/bullet-list/index.cjs.map +1 -1
  3. package/dist/bullet-list/index.js +19 -0
  4. package/dist/bullet-list/index.js.map +1 -1
  5. package/dist/index.cjs +413 -5
  6. package/dist/index.cjs.map +1 -1
  7. package/dist/index.d.cts +3 -3
  8. package/dist/index.d.ts +3 -3
  9. package/dist/index.js +422 -8
  10. package/dist/index.js.map +1 -1
  11. package/dist/item/index.cjs +61 -0
  12. package/dist/item/index.cjs.map +1 -1
  13. package/dist/item/index.js +62 -1
  14. package/dist/item/index.js.map +1 -1
  15. package/dist/keymap/index.d.cts +2 -2
  16. package/dist/keymap/index.d.ts +2 -2
  17. package/dist/kit/index.cjs +413 -5
  18. package/dist/kit/index.cjs.map +1 -1
  19. package/dist/kit/index.js +422 -8
  20. package/dist/kit/index.js.map +1 -1
  21. package/dist/ordered-list/index.cjs +189 -0
  22. package/dist/ordered-list/index.cjs.map +1 -1
  23. package/dist/ordered-list/index.js +189 -0
  24. package/dist/ordered-list/index.js.map +1 -1
  25. package/dist/task-item/index.cjs +53 -5
  26. package/dist/task-item/index.cjs.map +1 -1
  27. package/dist/task-item/index.d.cts +1 -1
  28. package/dist/task-item/index.d.ts +1 -1
  29. package/dist/task-item/index.js +60 -6
  30. package/dist/task-item/index.js.map +1 -1
  31. package/dist/task-list/index.cjs +91 -0
  32. package/dist/task-list/index.cjs.map +1 -1
  33. package/dist/task-list/index.js +92 -1
  34. package/dist/task-list/index.js.map +1 -1
  35. package/package.json +5 -5
  36. package/src/bullet-list/bullet-list.ts +25 -0
  37. package/src/item/list-item.ts +82 -1
  38. package/src/ordered-list/ordered-list.ts +72 -0
  39. package/src/ordered-list/utils.ts +234 -0
  40. package/src/task-item/task-item.ts +87 -8
  41. package/src/task-list/task-list.ts +105 -1
@@ -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,67 @@ 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
+ var _a, _b;
180
+ if (context.parentType === "bulletList") {
181
+ return "- ";
182
+ }
183
+ if (context.parentType === "orderedList") {
184
+ const start = ((_b = (_a = context.meta) == null ? void 0 : _a.parentAttrs) == null ? void 0 : _b.start) || 1;
185
+ return `${start + context.index}. `;
186
+ }
187
+ return "- ";
188
+ },
189
+ ctx
190
+ );
191
+ },
112
192
  addKeyboardShortcuts() {
113
193
  return {
114
194
  Enter: () => this.editor.commands.splitListItem(this.name),
@@ -396,6 +476,138 @@ var ListKeymap = import_core8.Extension.create({
396
476
 
397
477
  // src/ordered-list/ordered-list.ts
398
478
  var import_core9 = require("@tiptap/core");
479
+
480
+ // src/ordered-list/utils.ts
481
+ var ORDERED_LIST_ITEM_REGEX = /^(\s*)(\d+)\.\s+(.*)$/;
482
+ var INDENTED_LINE_REGEX = /^\s/;
483
+ function collectOrderedListItems(lines) {
484
+ const listItems = [];
485
+ let currentLineIndex = 0;
486
+ let consumed = 0;
487
+ while (currentLineIndex < lines.length) {
488
+ const line = lines[currentLineIndex];
489
+ const match = line.match(ORDERED_LIST_ITEM_REGEX);
490
+ if (!match) {
491
+ break;
492
+ }
493
+ const [, indent, number, content] = match;
494
+ const indentLevel = indent.length;
495
+ let itemContent = content;
496
+ let nextLineIndex = currentLineIndex + 1;
497
+ const itemLines = [line];
498
+ while (nextLineIndex < lines.length) {
499
+ const nextLine = lines[nextLineIndex];
500
+ const nextMatch = nextLine.match(ORDERED_LIST_ITEM_REGEX);
501
+ if (nextMatch) {
502
+ break;
503
+ }
504
+ if (nextLine.trim() === "") {
505
+ itemLines.push(nextLine);
506
+ itemContent += "\n";
507
+ nextLineIndex += 1;
508
+ } else if (nextLine.match(INDENTED_LINE_REGEX)) {
509
+ itemLines.push(nextLine);
510
+ itemContent += `
511
+ ${nextLine.slice(indentLevel + 2)}`;
512
+ nextLineIndex += 1;
513
+ } else {
514
+ break;
515
+ }
516
+ }
517
+ listItems.push({
518
+ indent: indentLevel,
519
+ number: parseInt(number, 10),
520
+ content: itemContent.trim(),
521
+ raw: itemLines.join("\n")
522
+ });
523
+ consumed = nextLineIndex;
524
+ currentLineIndex = nextLineIndex;
525
+ }
526
+ return [listItems, consumed];
527
+ }
528
+ function buildNestedStructure(items, baseIndent, lexer) {
529
+ var _a;
530
+ const result = [];
531
+ let currentIndex = 0;
532
+ while (currentIndex < items.length) {
533
+ const item = items[currentIndex];
534
+ if (item.indent === baseIndent) {
535
+ const contentLines = item.content.split("\n");
536
+ const mainText = ((_a = contentLines[0]) == null ? void 0 : _a.trim()) || "";
537
+ const tokens = [];
538
+ if (mainText) {
539
+ tokens.push({
540
+ type: "paragraph",
541
+ raw: mainText,
542
+ tokens: lexer.inlineTokens(mainText)
543
+ });
544
+ }
545
+ const additionalContent = contentLines.slice(1).join("\n").trim();
546
+ if (additionalContent) {
547
+ const blockTokens = lexer.blockTokens(additionalContent);
548
+ tokens.push(...blockTokens);
549
+ }
550
+ let lookAheadIndex = currentIndex + 1;
551
+ const nestedItems = [];
552
+ while (lookAheadIndex < items.length && items[lookAheadIndex].indent > baseIndent) {
553
+ nestedItems.push(items[lookAheadIndex]);
554
+ lookAheadIndex += 1;
555
+ }
556
+ if (nestedItems.length > 0) {
557
+ const nextIndent = Math.min(...nestedItems.map((nestedItem) => nestedItem.indent));
558
+ const nestedListItems = buildNestedStructure(nestedItems, nextIndent, lexer);
559
+ tokens.push({
560
+ type: "list",
561
+ ordered: true,
562
+ start: nestedItems[0].number,
563
+ items: nestedListItems,
564
+ raw: nestedItems.map((nestedItem) => nestedItem.raw).join("\n")
565
+ });
566
+ }
567
+ result.push({
568
+ type: "list_item",
569
+ raw: item.raw,
570
+ tokens
571
+ });
572
+ currentIndex = lookAheadIndex;
573
+ } else {
574
+ currentIndex += 1;
575
+ }
576
+ }
577
+ return result;
578
+ }
579
+ function parseListItems(items, helpers) {
580
+ return items.map((item) => {
581
+ if (item.type !== "list_item") {
582
+ return helpers.parseChildren([item])[0];
583
+ }
584
+ const content = [];
585
+ if (item.tokens && item.tokens.length > 0) {
586
+ item.tokens.forEach((itemToken) => {
587
+ if (itemToken.type === "paragraph" || itemToken.type === "list" || itemToken.type === "blockquote" || itemToken.type === "code") {
588
+ content.push(...helpers.parseChildren([itemToken]));
589
+ } else if (itemToken.type === "text" && itemToken.tokens) {
590
+ const inlineContent = helpers.parseChildren([itemToken]);
591
+ content.push({
592
+ type: "paragraph",
593
+ content: inlineContent
594
+ });
595
+ } else {
596
+ const parsed = helpers.parseChildren([itemToken]);
597
+ if (parsed.length > 0) {
598
+ content.push(...parsed);
599
+ }
600
+ }
601
+ });
602
+ }
603
+ return {
604
+ type: "listItem",
605
+ content
606
+ };
607
+ });
608
+ }
609
+
610
+ // src/ordered-list/ordered-list.ts
399
611
  var ListItemName2 = "listItem";
400
612
  var TextStyleName2 = "textStyle";
401
613
  var orderedListInputRegex = /^(\d+)\.\s$/;
@@ -438,6 +650,63 @@ var OrderedList = import_core9.Node.create({
438
650
  const { start, ...attributesWithoutStart } = HTMLAttributes;
439
651
  return start === 1 ? ["ol", (0, import_core9.mergeAttributes)(this.options.HTMLAttributes, attributesWithoutStart), 0] : ["ol", (0, import_core9.mergeAttributes)(this.options.HTMLAttributes, HTMLAttributes), 0];
440
652
  },
653
+ markdownTokenName: "list",
654
+ parseMarkdown: (token, helpers) => {
655
+ if (token.type !== "list" || !token.ordered) {
656
+ return [];
657
+ }
658
+ const startValue = token.start || 1;
659
+ const content = token.items ? parseListItems(token.items, helpers) : [];
660
+ if (startValue !== 1) {
661
+ return {
662
+ type: "orderedList",
663
+ attrs: { start: startValue },
664
+ content
665
+ };
666
+ }
667
+ return {
668
+ type: "orderedList",
669
+ content
670
+ };
671
+ },
672
+ renderMarkdown: (node, h) => {
673
+ if (!node.content) {
674
+ return "";
675
+ }
676
+ return h.renderChildren(node.content, "\n");
677
+ },
678
+ markdownTokenizer: {
679
+ name: "orderedList",
680
+ level: "block",
681
+ start: (src) => {
682
+ const match = src.match(/^(\s*)(\d+)\.\s+/);
683
+ const index = match == null ? void 0 : match.index;
684
+ return index !== void 0 ? index : -1;
685
+ },
686
+ tokenize: (src, _tokens, lexer) => {
687
+ var _a;
688
+ const lines = src.split("\n");
689
+ const [listItems, consumed] = collectOrderedListItems(lines);
690
+ if (listItems.length === 0) {
691
+ return void 0;
692
+ }
693
+ const items = buildNestedStructure(listItems, 0, lexer);
694
+ if (items.length === 0) {
695
+ return void 0;
696
+ }
697
+ const startValue = ((_a = listItems[0]) == null ? void 0 : _a.number) || 1;
698
+ return {
699
+ type: "list",
700
+ ordered: true,
701
+ start: startValue,
702
+ items,
703
+ raw: lines.slice(0, consumed).join("\n")
704
+ };
705
+ }
706
+ },
707
+ markdownOptions: {
708
+ indentsContent: true
709
+ },
441
710
  addCommands() {
442
711
  return {
443
712
  toggleOrderedList: () => ({ commands, chain }) => {
@@ -477,7 +746,7 @@ var OrderedList = import_core9.Node.create({
477
746
 
478
747
  // src/task-item/task-item.ts
479
748
  var import_core10 = require("@tiptap/core");
480
- var inputRegex = /^\s*(\[([( |x])?\])\s$/;
749
+ var inputRegex = /^\s*((\[([( |x])?\])|\.)\s$/;
481
750
  var TaskItem = import_core10.Node.create({
482
751
  name: "taskItem",
483
752
  addOptions() {
@@ -535,6 +804,27 @@ var TaskItem = import_core10.Node.create({
535
804
  ["div", 0]
536
805
  ];
537
806
  },
807
+ parseMarkdown: (token, h) => {
808
+ const content = [];
809
+ if (token.tokens && token.tokens.length > 0) {
810
+ content.push(h.createNode("paragraph", {}, h.parseInline(token.tokens)));
811
+ } else if (token.text) {
812
+ content.push(h.createNode("paragraph", {}, [h.createNode("text", { text: token.text })]));
813
+ } else {
814
+ content.push(h.createNode("paragraph", {}, []));
815
+ }
816
+ if (token.nestedTokens && token.nestedTokens.length > 0) {
817
+ const nestedContent = h.parseChildren(token.nestedTokens);
818
+ content.push(...nestedContent);
819
+ }
820
+ return h.createNode("taskItem", { checked: token.checked || false }, content);
821
+ },
822
+ renderMarkdown: (node, h) => {
823
+ var _a;
824
+ const checkedChar = ((_a = node.attrs) == null ? void 0 : _a.checked) ? "x" : " ";
825
+ const prefix = `- [${checkedChar}] `;
826
+ return (0, import_core10.renderNestedMarkdownContent)(node, h, prefix);
827
+ },
538
828
  addKeyboardShortcuts() {
539
829
  const shortcuts = {
540
830
  Enter: () => this.editor.commands.splitListItem(this.name),
@@ -555,13 +845,14 @@ var TaskItem = import_core10.Node.create({
555
845
  const checkboxStyler = document.createElement("span");
556
846
  const checkbox = document.createElement("input");
557
847
  const content = document.createElement("div");
558
- const updateA11Y = () => {
848
+ const updateA11Y = (currentNode) => {
559
849
  var _a, _b;
560
- checkbox.ariaLabel = ((_b = (_a = this.options.a11y) == null ? void 0 : _a.checkboxLabel) == null ? void 0 : _b.call(_a, node, checkbox.checked)) || `Task item checkbox for ${node.textContent || "empty task item"}`;
850
+ checkbox.ariaLabel = ((_b = (_a = this.options.a11y) == null ? void 0 : _a.checkboxLabel) == null ? void 0 : _b.call(_a, currentNode, checkbox.checked)) || `Task item checkbox for ${currentNode.textContent || "empty task item"}`;
561
851
  };
562
- updateA11Y();
852
+ updateA11Y(node);
563
853
  checkboxWrapper.contentEditable = "false";
564
854
  checkbox.type = "checkbox";
855
+ checkbox.contentEditable = "false";
565
856
  checkbox.addEventListener("mousedown", (event) => event.preventDefault());
566
857
  checkbox.addEventListener("change", (event) => {
567
858
  if (!editor.isEditable && !this.options.onReadOnlyChecked) {
@@ -614,6 +905,7 @@ var TaskItem = import_core10.Node.create({
614
905
  Object.entries(HTMLAttributes).forEach(([key, value]) => {
615
906
  listItem.setAttribute(key, value);
616
907
  });
908
+ let prevRenderedAttributeKeys = new Set(Object.keys(HTMLAttributes));
617
909
  return {
618
910
  dom: listItem,
619
911
  contentDOM: content,
@@ -623,7 +915,32 @@ var TaskItem = import_core10.Node.create({
623
915
  }
624
916
  listItem.dataset.checked = updatedNode.attrs.checked;
625
917
  checkbox.checked = updatedNode.attrs.checked;
626
- updateA11Y();
918
+ updateA11Y(updatedNode);
919
+ const extensionAttributes = editor.extensionManager.attributes;
920
+ const newHTMLAttributes = (0, import_core10.getRenderedAttributes)(updatedNode, extensionAttributes);
921
+ const newKeys = new Set(Object.keys(newHTMLAttributes));
922
+ const staticAttrs = this.options.HTMLAttributes;
923
+ prevRenderedAttributeKeys.forEach((key) => {
924
+ if (!newKeys.has(key)) {
925
+ if (key in staticAttrs) {
926
+ listItem.setAttribute(key, staticAttrs[key]);
927
+ } else {
928
+ listItem.removeAttribute(key);
929
+ }
930
+ }
931
+ });
932
+ Object.entries(newHTMLAttributes).forEach(([key, value]) => {
933
+ if (value === null || value === void 0) {
934
+ if (key in staticAttrs) {
935
+ listItem.setAttribute(key, staticAttrs[key]);
936
+ } else {
937
+ listItem.removeAttribute(key);
938
+ }
939
+ } else {
940
+ listItem.setAttribute(key, value);
941
+ }
942
+ });
943
+ prevRenderedAttributeKeys = newKeys;
627
944
  return true;
628
945
  }
629
946
  };
@@ -667,6 +984,97 @@ var TaskList = import_core11.Node.create({
667
984
  renderHTML({ HTMLAttributes }) {
668
985
  return ["ul", (0, import_core11.mergeAttributes)(this.options.HTMLAttributes, HTMLAttributes, { "data-type": this.name }), 0];
669
986
  },
987
+ parseMarkdown: (token, h) => {
988
+ return h.createNode("taskList", {}, h.parseChildren(token.items || []));
989
+ },
990
+ renderMarkdown: (node, h) => {
991
+ if (!node.content) {
992
+ return "";
993
+ }
994
+ return h.renderChildren(node.content, "\n");
995
+ },
996
+ markdownTokenizer: {
997
+ name: "taskList",
998
+ level: "block",
999
+ start(src) {
1000
+ var _a;
1001
+ const index = (_a = src.match(/^\s*[-+*]\s+\[([ xX])\]\s+/)) == null ? void 0 : _a.index;
1002
+ return index !== void 0 ? index : -1;
1003
+ },
1004
+ tokenize(src, tokens, lexer) {
1005
+ const parseTaskListContent = (content) => {
1006
+ const nestedResult = (0, import_core11.parseIndentedBlocks)(
1007
+ content,
1008
+ {
1009
+ itemPattern: /^(\s*)([-+*])\s+\[([ xX])\]\s+(.*)$/,
1010
+ extractItemData: (match) => ({
1011
+ indentLevel: match[1].length,
1012
+ mainContent: match[4],
1013
+ checked: match[3].toLowerCase() === "x"
1014
+ }),
1015
+ createToken: (data, nestedTokens) => ({
1016
+ type: "taskItem",
1017
+ raw: "",
1018
+ mainContent: data.mainContent,
1019
+ indentLevel: data.indentLevel,
1020
+ checked: data.checked,
1021
+ text: data.mainContent,
1022
+ tokens: lexer.inlineTokens(data.mainContent),
1023
+ nestedTokens
1024
+ }),
1025
+ // Allow recursive nesting
1026
+ customNestedParser: parseTaskListContent
1027
+ },
1028
+ lexer
1029
+ );
1030
+ if (nestedResult) {
1031
+ return [
1032
+ {
1033
+ type: "taskList",
1034
+ raw: nestedResult.raw,
1035
+ items: nestedResult.items
1036
+ }
1037
+ ];
1038
+ }
1039
+ return lexer.blockTokens(content);
1040
+ };
1041
+ const result = (0, import_core11.parseIndentedBlocks)(
1042
+ src,
1043
+ {
1044
+ itemPattern: /^(\s*)([-+*])\s+\[([ xX])\]\s+(.*)$/,
1045
+ extractItemData: (match) => ({
1046
+ indentLevel: match[1].length,
1047
+ mainContent: match[4],
1048
+ checked: match[3].toLowerCase() === "x"
1049
+ }),
1050
+ createToken: (data, nestedTokens) => ({
1051
+ type: "taskItem",
1052
+ raw: "",
1053
+ mainContent: data.mainContent,
1054
+ indentLevel: data.indentLevel,
1055
+ checked: data.checked,
1056
+ text: data.mainContent,
1057
+ tokens: lexer.inlineTokens(data.mainContent),
1058
+ nestedTokens
1059
+ }),
1060
+ // Use the recursive parser for nested content
1061
+ customNestedParser: parseTaskListContent
1062
+ },
1063
+ lexer
1064
+ );
1065
+ if (!result) {
1066
+ return void 0;
1067
+ }
1068
+ return {
1069
+ type: "taskList",
1070
+ raw: result.raw,
1071
+ items: result.items
1072
+ };
1073
+ }
1074
+ },
1075
+ markdownOptions: {
1076
+ indentsContent: true
1077
+ },
670
1078
  addCommands() {
671
1079
  return {
672
1080
  toggleTaskList: () => ({ commands }) => {