fix: button rendering from RichEditor to markdown to HTML

- Added multiple htmlToMarkdown patterns for TipTap button output:
  1. data-button with data-href/data-style attributes
  2. Alternate attribute order (data-style before data-href)
  3. Simple data-button fallback with href and class
  4. Buttons wrapped in p tags (from preview HTML)
  5. Direct button links without p wrapper

- Button shortcodes now correctly roundtrip:
  RichEditor -> HTML -> [button url=... style=...] -> Preview/Email

- All patterns now explicitly include style=solid for consistency
This commit is contained in:
Dwindi Ramadhana
2026-01-01 21:37:55 +07:00
parent ccdd88a629
commit e84fa969bb

View File

@@ -267,8 +267,33 @@ export function htmlToMarkdown(html: string): string {
});
// Convert buttons back to [button] syntax
// TipTap button format with data attributes: <a data-button data-href="..." data-style="..." data-text="...">text</a>
markdown = markdown.replace(/<a[^>]*data-button[^>]*data-href="([^"]+)"[^>]*data-style="([^"]*)"[^>]*>([^<]+)<\/a>/gi, (match, url, style, text) => {
const styleAttr = style === 'outline' ? ' style="outline"' : ' style="solid"';
return `[button url="${url}"${styleAttr}]${text.trim()}[/button]`;
});
// Alternate order: data-style before data-href
markdown = markdown.replace(/<a[^>]*data-button[^>]*data-style="([^"]*)"[^>]*data-href="([^"]+)"[^>]*>([^<]+)<\/a>/gi, (match, style, url, text) => {
const styleAttr = style === 'outline' ? ' style="outline"' : ' style="solid"';
return `[button url="${url}"${styleAttr}]${text.trim()}[/button]`;
});
// Simple data-button fallback (just has href and class)
markdown = markdown.replace(/<a[^>]*href="([^"]+)"[^>]*class="(button[^"]*)"[^>]*data-button[^>]*>([^<]+)<\/a>/gi, (match, url, className, text) => {
const style = className.includes('outline') ? ' style="outline"' : ' style="solid"';
return `[button url="${url}"${style}]${text.trim()}[/button]`;
});
// Buttons wrapped in p tags (from preview HTML): <p><a href="..." class="button...">text</a></p>
markdown = markdown.replace(/<p[^>]*><a href="([^"]+)" class="(button[^"]*)"[^>]*>([^<]+)<\/a><\/p>/g, (match, url, className, text) => {
const style = className.includes('outline') ? ' style="outline"' : '';
const style = className.includes('outline') ? ' style="outline"' : ' style="solid"';
return `[button url="${url}"${style}]${text.trim()}[/button]`;
});
// Direct button links without p wrapper
markdown = markdown.replace(/<a href="([^"]+)" class="(button[^"]*)"[^>]*>([^<]+)<\/a>/g, (match, url, className, text) => {
const style = className.includes('outline') ? ' style="outline"' : ' style="solid"';
return `[button url="${url}"${style}]${text.trim()}[/button]`;
});