@uniweb/content-reader 1.1.2 → 1.1.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniweb/content-reader",
3
- "version": "1.1.2",
3
+ "version": "1.1.4",
4
4
  "description": "Markdown to ProseMirror document structure converter",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -111,7 +111,10 @@ function parseBlock(token, schema) {
111
111
  let currentParagraph = null;
112
112
 
113
113
  content.forEach((element) => {
114
- if (element.type === "image" && element.attrs?.role !== "icon") {
114
+ if (
115
+ (element.type === "image" && element.attrs?.role !== "icon") ||
116
+ element.type === "inset_ref"
117
+ ) {
115
118
  // Extract non-icon images to root level so they become
116
119
  // block-level elements. Icons stay inline so the semantic
117
120
  // parser can associate them with adjacent links.
@@ -148,6 +148,20 @@ function parseInline(token, schema, removeNewLine = false) {
148
148
  }
149
149
 
150
150
  if (token.type === "image") {
151
+ // Check for @ component reference: ![alt](@ComponentName){key=value}
152
+ if (token.href.startsWith('@') && token.href.length > 1) {
153
+ const component = token.href.slice(1)
154
+ const { role: _role, ...otherAttrs } = token.attrs || {}
155
+ return [{
156
+ type: "inset_ref",
157
+ attrs: {
158
+ component,
159
+ alt: text || null,
160
+ ...otherAttrs,
161
+ },
162
+ }]
163
+ }
164
+
151
165
  let role, src, iconLibrary, iconName;
152
166
 
153
167
  // Supported icon families - friendly names and direct react-icons codes
@@ -60,6 +60,22 @@ const baseNodes = {
60
60
  // group: "block inline",
61
61
  },
62
62
 
63
+ inset_ref: {
64
+ attrs: {
65
+ component: {},
66
+ alt: { default: null },
67
+ // Dynamic attributes from {key=value} syntax are also stored here
68
+ },
69
+ group: "block",
70
+ },
71
+
72
+ inset_placeholder: {
73
+ attrs: {
74
+ refId: {},
75
+ },
76
+ group: "block",
77
+ },
78
+
63
79
  divider: {
64
80
  attrs: {
65
81
  style: { default: "line" },
@@ -699,3 +699,87 @@ describe("Bracketed Spans", () => {
699
699
  expect(content[2].marks[0].attrs.class).toBe("muted");
700
700
  });
701
701
  });
702
+
703
+ describe("Component References (@)", () => {
704
+ test("parses bare @ComponentName", () => {
705
+ const markdown = "![](@Hero)";
706
+ const result = markdownToProseMirror(markdown);
707
+
708
+ expect(result).toEqual({
709
+ type: "doc",
710
+ content: [
711
+ {
712
+ type: "inline_child_ref",
713
+ attrs: {
714
+ component: "Hero",
715
+ alt: null,
716
+ },
717
+ },
718
+ ],
719
+ });
720
+ });
721
+
722
+ test("parses @ComponentName with alt text and params", () => {
723
+ const markdown = "![Architecture diagram](@NetworkDiagram){variant=compact size=lg}";
724
+ const result = markdownToProseMirror(markdown);
725
+
726
+ expect(result).toEqual({
727
+ type: "doc",
728
+ content: [
729
+ {
730
+ type: "inline_child_ref",
731
+ attrs: {
732
+ component: "NetworkDiagram",
733
+ alt: "Architecture diagram",
734
+ variant: "compact",
735
+ size: "lg",
736
+ },
737
+ },
738
+ ],
739
+ });
740
+ });
741
+
742
+ test("bare @ is treated as regular image", () => {
743
+ const markdown = "![](@)";
744
+ const result = markdownToProseMirror(markdown);
745
+
746
+ // Bare @ doesn't match component ref (length check), falls through to image
747
+ expect(result.content[0].type).toBe("image");
748
+ });
749
+
750
+ test("@ ref is lifted to block level (not inline in paragraph)", () => {
751
+ const markdown = "Some text before ![](@Widget) and after";
752
+ const result = markdownToProseMirror(markdown);
753
+
754
+ // inline_child_ref should be extracted from paragraph like images
755
+ const types = result.content.map((n) => n.type);
756
+ expect(types).toContain("inline_child_ref");
757
+ expect(types).toContain("paragraph");
758
+ });
759
+
760
+ test("icon syntax is not affected by @ detection", () => {
761
+ const markdown = "![](lu-house)";
762
+ const result = markdownToProseMirror(markdown);
763
+
764
+ // Icons still work as before
765
+ expect(result.content[0].type).toBe("paragraph");
766
+ expect(result.content[0].content[0].attrs.role).toBe("icon");
767
+ expect(result.content[0].content[0].attrs.library).toBe("lu");
768
+ expect(result.content[0].content[0].attrs.name).toBe("house");
769
+ });
770
+
771
+ test("multiple @ refs in same section", () => {
772
+ const markdown = "![](@Widget)\n\n![](@Chart)";
773
+ const result = markdownToProseMirror(markdown);
774
+
775
+ expect(result.content).toHaveLength(2);
776
+ expect(result.content[0]).toEqual({
777
+ type: "inline_child_ref",
778
+ attrs: { component: "Widget", alt: null },
779
+ });
780
+ expect(result.content[1]).toEqual({
781
+ type: "inline_child_ref",
782
+ attrs: { component: "Chart", alt: null },
783
+ });
784
+ });
785
+ });