@bendyline/squisq-editor-react 1.3.0 → 1.4.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/dist/EditorShell.d.ts +12 -1
- package/dist/EditorShell.d.ts.map +1 -1
- package/dist/EditorShell.js +80 -8
- package/dist/EditorShell.js.map +1 -1
- package/dist/MediaBin.d.ts +12 -1
- package/dist/MediaBin.d.ts.map +1 -1
- package/dist/MediaBin.js +13 -3
- package/dist/MediaBin.js.map +1 -1
- package/dist/__tests__/mediaAttachmentFlow.test.d.ts +2 -0
- package/dist/__tests__/mediaAttachmentFlow.test.d.ts.map +1 -0
- package/dist/__tests__/mediaAttachmentFlow.test.js +99 -0
- package/dist/__tests__/mediaAttachmentFlow.test.js.map +1 -0
- package/dist/__tests__/tiptapBridge.test.js +13 -0
- package/dist/__tests__/tiptapBridge.test.js.map +1 -1
- package/dist/__tests__/tiptapImageRoundTrip.test.d.ts +2 -0
- package/dist/__tests__/tiptapImageRoundTrip.test.d.ts.map +1 -0
- package/dist/__tests__/tiptapImageRoundTrip.test.js +68 -0
- package/dist/__tests__/tiptapImageRoundTrip.test.js.map +1 -0
- package/dist/tiptapBridge.d.ts.map +1 -1
- package/dist/tiptapBridge.js +41 -4
- package/dist/tiptapBridge.js.map +1 -1
- package/package.json +1 -1
- package/src/EditorShell.tsx +120 -8
- package/src/MediaBin.tsx +22 -3
- package/src/__tests__/mediaAttachmentFlow.test.ts +110 -0
- package/src/__tests__/tiptapBridge.test.ts +14 -0
- package/src/__tests__/tiptapImageRoundTrip.test.ts +73 -0
- package/src/tiptapBridge.ts +41 -4
package/src/tiptapBridge.ts
CHANGED
|
@@ -19,7 +19,11 @@ const RE_ITALIC_UNDER = /_(.+?)_/g;
|
|
|
19
19
|
const RE_STRIKETHROUGH = /~~(.+?)~~/g;
|
|
20
20
|
const RE_INLINE_CODE = /`(.+?)`/g;
|
|
21
21
|
const RE_LINK = /\[(.+?)\]\((.+?)\)/g;
|
|
22
|
-
|
|
22
|
+
// `*?` on the alt — an empty alt (``) is valid markdown and
|
|
23
|
+
// the most common shape for pasted/uploaded images that don't yet have
|
|
24
|
+
// a human-picked caption. Previously required at least one alt char,
|
|
25
|
+
// which dropped those images on the floor during markdown→HTML.
|
|
26
|
+
const RE_IMAGE = /!\[(.*?)\]\((.+?)\)/g;
|
|
23
27
|
// Mentions: `@[Display](scheme:id)` — scheme-part must start with a letter
|
|
24
28
|
// so plain `$100` or price-style parentheticals don't accidentally match.
|
|
25
29
|
// remark-stringify may round-trip the colon as `\:` — tolerate either.
|
|
@@ -33,7 +37,14 @@ const RE_S_TAG = /<s>(.*?)<\/s>/g;
|
|
|
33
37
|
const RE_DEL_TAG = /<del>(.*?)<\/del>/g;
|
|
34
38
|
const RE_CODE_TAG = /<code>(.*?)<\/code>/g;
|
|
35
39
|
const RE_A_TAG = /<a[^>]+href="([^"]*)"[^>]*>(.*?)<\/a>/g;
|
|
36
|
-
|
|
40
|
+
// Matches any `<img>` tag and captures its `src` + `alt` regardless of
|
|
41
|
+
// attribute order. TipTap's Image extension renders `<img src="..."
|
|
42
|
+
// alt="...">` (src first), while some other producers — including our
|
|
43
|
+
// own `markdownToTiptap` conversion — emit alt-first. The previous
|
|
44
|
+
// regex required alt-before-src and silently dropped every src-first
|
|
45
|
+
// image; `RE_STRIP_TAGS` below would then delete the unmatched tag,
|
|
46
|
+
// so the outgoing markdown had no image reference at all.
|
|
47
|
+
const RE_IMG_TAG = /<img\b([^>]*)>/g;
|
|
37
48
|
const RE_STRIP_TAGS = /<[^>]+>/g;
|
|
38
49
|
|
|
39
50
|
/**
|
|
@@ -462,6 +473,26 @@ export function tiptapToMarkdown(html: string): string {
|
|
|
462
473
|
continue;
|
|
463
474
|
}
|
|
464
475
|
|
|
476
|
+
// Block-level image. TipTap's Image extension with `inline: false`
|
|
477
|
+
// emits `<img src alt>` as a bare top-level element (no wrapping
|
|
478
|
+
// `<p>`). Without this handler the skip-unknown-tags catch-all
|
|
479
|
+
// below silently drops the image from the outgoing markdown —
|
|
480
|
+
// the bug that made the chat composer ship image-less messages
|
|
481
|
+
// even though the editor showed the picture. Handled here,
|
|
482
|
+
// before the inline walker ever sees it.
|
|
483
|
+
const imgMatch = remaining.match(/^<img\b([^>]*)>/);
|
|
484
|
+
if (imgMatch) {
|
|
485
|
+
const attrs = imgMatch[1] ?? '';
|
|
486
|
+
const src = /\bsrc="([^"]*)"/i.exec(attrs)?.[1];
|
|
487
|
+
if (src) {
|
|
488
|
+
const alt = /\balt="([^"]*)"/i.exec(attrs)?.[1] ?? '';
|
|
489
|
+
lines.push(``);
|
|
490
|
+
lines.push('');
|
|
491
|
+
}
|
|
492
|
+
remaining = remaining.slice(imgMatch[0].length);
|
|
493
|
+
continue;
|
|
494
|
+
}
|
|
495
|
+
|
|
465
496
|
// Skip unknown tags or whitespace
|
|
466
497
|
const skipMatch = remaining.match(/^(<[^>]+>|\s+)/);
|
|
467
498
|
if (skipMatch) {
|
|
@@ -637,8 +668,14 @@ function htmlToInline(html: string): string {
|
|
|
637
668
|
// Links
|
|
638
669
|
result = result.replace(RE_A_TAG, '[$2]($1)');
|
|
639
670
|
|
|
640
|
-
// Images
|
|
641
|
-
|
|
671
|
+
// Images — order-agnostic attribute parsing (tiptap emits src-first,
|
|
672
|
+
// our markdown-to-html emits alt-first; either must serialize back).
|
|
673
|
+
result = result.replace(RE_IMG_TAG, (match, attrs: string) => {
|
|
674
|
+
const src = /\bsrc="([^"]*)"/i.exec(attrs)?.[1];
|
|
675
|
+
if (!src) return match;
|
|
676
|
+
const alt = /\balt="([^"]*)"/i.exec(attrs)?.[1] ?? '';
|
|
677
|
+
return ``;
|
|
678
|
+
});
|
|
642
679
|
|
|
643
680
|
// Strip remaining tags
|
|
644
681
|
result = result.replace(RE_STRIP_TAGS, '');
|