@uniweb/semantic-parser 1.0.16 → 1.1.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.
- package/package.json +1 -1
- package/src/processors/sequence.js +42 -18
package/package.json
CHANGED
|
@@ -47,6 +47,14 @@ function getCodeBlockData(text, attrs) {
|
|
|
47
47
|
return text;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Check if an inline node is an icon.
|
|
52
|
+
* TipTap editor uses type "UniwebIcon"; markdown pipeline uses type "image" with role "icon".
|
|
53
|
+
*/
|
|
54
|
+
function isIconNode(node) {
|
|
55
|
+
return node.type === "UniwebIcon" || (node.type === "image" && node.attrs?.role === "icon");
|
|
56
|
+
}
|
|
57
|
+
|
|
50
58
|
/**
|
|
51
59
|
* Process a ProseMirror/TipTap document into a flat sequence
|
|
52
60
|
* @param {Object} doc ProseMirror document
|
|
@@ -287,17 +295,27 @@ function getTextContent(content, options = {}) {
|
|
|
287
295
|
const spanMark = marks.find((mark) => mark.type === "span");
|
|
288
296
|
const attrs = spanMark?.attrs || {};
|
|
289
297
|
const attrParts = [];
|
|
298
|
+
const styleParts = [];
|
|
290
299
|
|
|
291
300
|
if (attrs.class) attrParts.push(`class="${attrs.class}"`);
|
|
292
301
|
if (attrs.id) attrParts.push(`id="${attrs.id}"`);
|
|
293
302
|
|
|
294
|
-
// Add any other custom attributes (data-*, etc.)
|
|
295
303
|
for (const [key, value] of Object.entries(attrs)) {
|
|
296
|
-
if (key
|
|
304
|
+
if (key === 'class' || key === 'id') continue;
|
|
305
|
+
// Convert color/bg to inline styles
|
|
306
|
+
if (key === 'color') {
|
|
307
|
+
styleParts.push(`color: ${value}`);
|
|
308
|
+
} else if (key === 'bg') {
|
|
309
|
+
styleParts.push(`background: ${value}`);
|
|
310
|
+
} else {
|
|
297
311
|
attrParts.push(`${key}="${value}"`);
|
|
298
312
|
}
|
|
299
313
|
}
|
|
300
314
|
|
|
315
|
+
if (styleParts.length > 0) {
|
|
316
|
+
attrParts.push(`style="${styleParts.join('; ')}"`)
|
|
317
|
+
}
|
|
318
|
+
|
|
301
319
|
const attrString = attrParts.length > 0 ? ` ${attrParts.join(' ')}` : '';
|
|
302
320
|
styledText = `<span${attrString}>${styledText}</span>`;
|
|
303
321
|
}
|
|
@@ -364,7 +382,7 @@ function processInlineElements(content) {
|
|
|
364
382
|
const items = [];
|
|
365
383
|
|
|
366
384
|
for (const item of content) {
|
|
367
|
-
if (item
|
|
385
|
+
if (isIconNode(item)) {
|
|
368
386
|
items.push({
|
|
369
387
|
type: "icon",
|
|
370
388
|
attrs: parseUniwebIcon(item.attrs),
|
|
@@ -455,17 +473,23 @@ function parseDocumentBlock(itemAttrs) {
|
|
|
455
473
|
}
|
|
456
474
|
|
|
457
475
|
function parseUniwebIcon(itemAttrs) {
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
476
|
+
const { svg, url, size, color, preserveColors, href, target, library, name } = itemAttrs || {};
|
|
477
|
+
|
|
478
|
+
// Build object with only defined fields — icon source varies:
|
|
479
|
+
// TipTap editor: svg/url (resolved inline)
|
|
480
|
+
// Markdown pipeline: library + name (resolved at runtime via CDN)
|
|
481
|
+
const icon = {};
|
|
482
|
+
if (svg) icon.svg = svg;
|
|
483
|
+
if (url) icon.url = url;
|
|
484
|
+
if (size) icon.size = size;
|
|
485
|
+
if (color) icon.color = color;
|
|
486
|
+
if (preserveColors) icon.preserveColors = preserveColors;
|
|
487
|
+
if (href) icon.href = href;
|
|
488
|
+
if (target) icon.target = target;
|
|
489
|
+
if (library) icon.library = library;
|
|
490
|
+
if (name) icon.name = name;
|
|
491
|
+
|
|
492
|
+
return icon;
|
|
469
493
|
}
|
|
470
494
|
|
|
471
495
|
function parseIconBlock(itemAttrs) {
|
|
@@ -581,7 +605,7 @@ function isLink(item) {
|
|
|
581
605
|
|
|
582
606
|
// Filter out icons and whitespace to check for single link
|
|
583
607
|
const textContent = originalContent.filter((c) => {
|
|
584
|
-
if (c
|
|
608
|
+
if (isIconNode(c)) {
|
|
585
609
|
return false;
|
|
586
610
|
} else if (c.type === "text") {
|
|
587
611
|
return (c.text || "").trim() !== "";
|
|
@@ -607,7 +631,7 @@ function isLink(item) {
|
|
|
607
631
|
let iconAfter = null;
|
|
608
632
|
|
|
609
633
|
for (let i = 0; i < originalContent.length; i++) {
|
|
610
|
-
if (originalContent[i]
|
|
634
|
+
if (isIconNode(originalContent[i])) {
|
|
611
635
|
const iconAttrs = parseUniwebIcon(originalContent[i].attrs);
|
|
612
636
|
if (i < linkIndex) {
|
|
613
637
|
// Take the last icon before the link
|
|
@@ -657,7 +681,7 @@ function isOnlyLinks(item) {
|
|
|
657
681
|
|
|
658
682
|
// Filter to get only significant content (no icons, no whitespace)
|
|
659
683
|
const textContent = content.filter((c) => {
|
|
660
|
-
if (c
|
|
684
|
+
if (isIconNode(c)) return false;
|
|
661
685
|
if (c.type === "text" && !(c.text || "").trim()) return false;
|
|
662
686
|
return true;
|
|
663
687
|
});
|
|
@@ -698,7 +722,7 @@ function isStyledLink(item) {
|
|
|
698
722
|
if (!content.length) return false;
|
|
699
723
|
|
|
700
724
|
content = content.filter((c) => {
|
|
701
|
-
if (c
|
|
725
|
+
if (isIconNode(c)) {
|
|
702
726
|
return false;
|
|
703
727
|
}
|
|
704
728
|
|