@uniweb/semantic-parser 1.2.1 → 1.2.2

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/semantic-parser",
3
- "version": "1.2.1",
3
+ "version": "1.2.2",
4
4
  "description": "Semantic parser for ProseMirror/TipTap content structures",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
@@ -470,10 +470,23 @@ function getTextContent(content, options = {}) {
470
470
  }
471
471
  }
472
472
 
473
+ // Icons are emitted as positional markers that a renderer swaps for a real
474
+ // component (see renderInlineNode). The marker carries the icon's ordinal
475
+ // among the icons of THIS content array, which is the same order
476
+ // processInlineElements() puts them in `children` — so a consumer resolves
477
+ // one with `children.filter(c => c.type === 'icon')[index]`. Referencing by
478
+ // ordinal rather than serializing the attrs keeps an inline `svg` blob out
479
+ // of the text stream and leaves `children` the single source of truth.
480
+ const iconOrdinals = new Map();
481
+ let nextIcon = 0;
482
+ for (const node of content) {
483
+ if (isIconNode(node)) iconOrdinals.set(node, nextIcon++);
484
+ }
485
+
473
486
  return groups
474
487
  .reduce((prev, group) => {
475
488
  const inner = group.nodes.reduce(
476
- (acc, node) => acc + renderInlineNode(node),
489
+ (acc, node) => acc + renderInlineNode(node, iconOrdinals),
477
490
  "",
478
491
  );
479
492
  if (!inner && !group.link) return prev;
@@ -486,7 +499,7 @@ function getTextContent(content, options = {}) {
486
499
  * Render one inline node to HTML, applying every mark EXCEPT link — the
487
500
  * anchor is applied per group by getTextContent, since it may span nodes.
488
501
  */
489
- function renderInlineNode(curr) {
502
+ function renderInlineNode(curr, iconOrdinals) {
490
503
  return [curr]
491
504
  .reduce((prev, curr) => {
492
505
  const { type, marks = [], text } = curr;
@@ -593,6 +606,21 @@ function renderInlineNode(curr) {
593
606
  return prev + `<uniweb-inset data-ref-id="${refId}"></uniweb-inset>`;
594
607
  } else if (type === "hardBreak") {
595
608
  return prev + "<br>";
609
+ } else if (isIconNode(curr)) {
610
+ // An icon sitting IN the prose — `Click the ![](lu-save) button`.
611
+ // It rides as a positional marker for the same reason an inline
612
+ // inset does: the paragraph's text is an HTML string, and an
613
+ // icon needs a component (kit's <Icon>, which resolves the
614
+ // library+name against the icon CDN at render time).
615
+ //
616
+ // Until 2026-08-12 this fell through to the catch-all below and
617
+ // the icon vanished — the text kept a gap where it had been, the
618
+ // entry stayed in `children` and in `content.icons`, and nothing
619
+ // put it back. Every other inline atom (math, insets) already
620
+ // had a marker; this was the one that did not.
621
+ const index = iconOrdinals?.get(curr);
622
+ if (index === undefined) return prev;
623
+ return prev + `<uniweb-icon data-index="${index}"></uniweb-icon>`;
596
624
  } else {
597
625
  // console.warn(`unhandled text content type: ${type}`, curr);
598
626
  return prev;