@marvalt/wparser 0.1.3 → 0.1.5
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/README.md +2 -0
- package/dist/index.cjs +352 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +83 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +340 -28
- package/dist/index.esm.js.map +1 -1
- package/dist/registry/defaultRegistry.d.ts.map +1 -1
- package/dist/utils/cfImages.d.ts +18 -0
- package/dist/utils/cfImages.d.ts.map +1 -0
- package/dist/utils/contentExtractor.d.ts +28 -0
- package/dist/utils/contentExtractor.d.ts.map +1 -0
- package/dist/utils/styleMapper.d.ts +35 -0
- package/dist/utils/styleMapper.d.ts.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -57,6 +57,8 @@ const registry = createDefaultRegistry();
|
|
|
57
57
|
|
|
58
58
|
## Supported core blocks (default registry)
|
|
59
59
|
- paragraph, heading, image, list, list-item, group, columns, column, separator, buttons/button, quote, code, preformatted, table (+ row/cell)
|
|
60
|
+
- **cover** - Hero sections with background images, overlays, and inner content
|
|
61
|
+
- **media-text** - Side-by-side media and text layouts with responsive stacking
|
|
60
62
|
|
|
61
63
|
## Custom renderers
|
|
62
64
|
Extend or replace mappings:
|
package/dist/index.cjs
CHANGED
|
@@ -1506,51 +1506,354 @@ function renderTextWithShortcodes(text, registry) {
|
|
|
1506
1506
|
return parts;
|
|
1507
1507
|
}
|
|
1508
1508
|
|
|
1509
|
+
/**
|
|
1510
|
+
* Content extraction utilities for WordPress blocks
|
|
1511
|
+
* Extracts text content from various block formats
|
|
1512
|
+
*/
|
|
1513
|
+
/**
|
|
1514
|
+
* Extract text content from a block's innerHTML by stripping HTML tags
|
|
1515
|
+
*/
|
|
1516
|
+
function extractTextFromHTML(html) {
|
|
1517
|
+
if (!html)
|
|
1518
|
+
return '';
|
|
1519
|
+
// Remove HTML tags and decode entities
|
|
1520
|
+
const text = html
|
|
1521
|
+
.replace(/<[^>]*>/g, '') // Remove HTML tags
|
|
1522
|
+
.replace(/ /g, ' ') // Replace with space
|
|
1523
|
+
.replace(/’/g, "'") // Replace apostrophe entity
|
|
1524
|
+
.replace(/“/g, '"') // Replace left double quote
|
|
1525
|
+
.replace(/”/g, '"') // Replace right double quote
|
|
1526
|
+
.replace(/…/g, '...') // Replace ellipsis
|
|
1527
|
+
.replace(/&/g, '&') // Replace &
|
|
1528
|
+
.replace(/</g, '<') // Replace <
|
|
1529
|
+
.replace(/>/g, '>') // Replace >
|
|
1530
|
+
.replace(/"/g, '"') // Replace "
|
|
1531
|
+
.trim();
|
|
1532
|
+
return text;
|
|
1533
|
+
}
|
|
1534
|
+
/**
|
|
1535
|
+
* Extract text content from block attributes or innerHTML
|
|
1536
|
+
*/
|
|
1537
|
+
function getBlockTextContent(block) {
|
|
1538
|
+
const attrs = block.attributes || {};
|
|
1539
|
+
// Try various attribute keys
|
|
1540
|
+
const content = attrs['content'] || attrs['text'] || attrs['value'] || '';
|
|
1541
|
+
if (typeof content === 'string' && content.trim()) {
|
|
1542
|
+
return content.trim();
|
|
1543
|
+
}
|
|
1544
|
+
// Fall back to innerHTML
|
|
1545
|
+
if (block.innerHTML) {
|
|
1546
|
+
return extractTextFromHTML(block.innerHTML);
|
|
1547
|
+
}
|
|
1548
|
+
return '';
|
|
1549
|
+
}
|
|
1550
|
+
/**
|
|
1551
|
+
* Extract image URL from block attributes
|
|
1552
|
+
* Checks for Cloudflare URLs first, then falls back to regular URLs
|
|
1553
|
+
*/
|
|
1554
|
+
function getImageUrl(block) {
|
|
1555
|
+
const attrs = block.attributes || {};
|
|
1556
|
+
// Check various possible URL attributes
|
|
1557
|
+
const url = attrs['url'] ||
|
|
1558
|
+
attrs['src'] ||
|
|
1559
|
+
attrs['imageUrl'] ||
|
|
1560
|
+
attrs['mediaUrl'] ||
|
|
1561
|
+
attrs['backgroundImage'];
|
|
1562
|
+
if (typeof url === 'string' && url.trim()) {
|
|
1563
|
+
return url.trim();
|
|
1564
|
+
}
|
|
1565
|
+
// Try to extract from innerHTML if it's an img tag
|
|
1566
|
+
if (block.innerHTML) {
|
|
1567
|
+
const imgMatch = block.innerHTML.match(/src=["']([^"']+)["']/);
|
|
1568
|
+
if (imgMatch && imgMatch[1]) {
|
|
1569
|
+
return imgMatch[1];
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1572
|
+
return null;
|
|
1573
|
+
}
|
|
1574
|
+
/**
|
|
1575
|
+
* Extract image attributes (alt, width, height) from block
|
|
1576
|
+
*/
|
|
1577
|
+
function getImageAttributes(block) {
|
|
1578
|
+
const attrs = block.attributes || {};
|
|
1579
|
+
const url = getImageUrl(block);
|
|
1580
|
+
return {
|
|
1581
|
+
url,
|
|
1582
|
+
alt: attrs['alt'] || '',
|
|
1583
|
+
width: attrs['width'] ? Number(attrs['width']) : undefined,
|
|
1584
|
+
height: attrs['height'] ? Number(attrs['height']) : undefined,
|
|
1585
|
+
};
|
|
1586
|
+
}
|
|
1587
|
+
|
|
1588
|
+
/**
|
|
1589
|
+
* Style mapping utilities
|
|
1590
|
+
* Maps WordPress block attributes to Tailwind CSS classes
|
|
1591
|
+
*/
|
|
1592
|
+
/**
|
|
1593
|
+
* Map WordPress alignment to Tailwind classes
|
|
1594
|
+
*/
|
|
1595
|
+
function getAlignmentClasses(align) {
|
|
1596
|
+
if (!align)
|
|
1597
|
+
return '';
|
|
1598
|
+
switch (align) {
|
|
1599
|
+
case 'full':
|
|
1600
|
+
return 'w-full';
|
|
1601
|
+
case 'wide':
|
|
1602
|
+
return 'max-w-7xl mx-auto';
|
|
1603
|
+
case 'center':
|
|
1604
|
+
return 'mx-auto';
|
|
1605
|
+
case 'left':
|
|
1606
|
+
return 'mr-auto';
|
|
1607
|
+
case 'right':
|
|
1608
|
+
return 'ml-auto';
|
|
1609
|
+
default:
|
|
1610
|
+
return '';
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1613
|
+
/**
|
|
1614
|
+
* Map WordPress text alignment to Tailwind classes
|
|
1615
|
+
*/
|
|
1616
|
+
function getTextAlignClasses(textAlign) {
|
|
1617
|
+
if (!textAlign)
|
|
1618
|
+
return '';
|
|
1619
|
+
switch (textAlign) {
|
|
1620
|
+
case 'center':
|
|
1621
|
+
return 'text-center';
|
|
1622
|
+
case 'left':
|
|
1623
|
+
return 'text-left';
|
|
1624
|
+
case 'right':
|
|
1625
|
+
return 'text-right';
|
|
1626
|
+
default:
|
|
1627
|
+
return '';
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
/**
|
|
1631
|
+
* Map WordPress font size to Tailwind classes
|
|
1632
|
+
*/
|
|
1633
|
+
function getFontSizeClasses(fontSize) {
|
|
1634
|
+
if (!fontSize)
|
|
1635
|
+
return '';
|
|
1636
|
+
// Map WordPress font sizes to Tailwind
|
|
1637
|
+
const sizeMap = {
|
|
1638
|
+
'small': 'text-sm',
|
|
1639
|
+
'medium': 'text-base',
|
|
1640
|
+
'large': 'text-lg',
|
|
1641
|
+
'x-large': 'text-xl',
|
|
1642
|
+
'xx-large': 'text-3xl',
|
|
1643
|
+
'xxx-large': 'text-4xl',
|
|
1644
|
+
};
|
|
1645
|
+
return sizeMap[fontSize] || '';
|
|
1646
|
+
}
|
|
1647
|
+
/**
|
|
1648
|
+
* Get container classes based on layout and alignment
|
|
1649
|
+
*/
|
|
1650
|
+
function getContainerClasses(align, layout) {
|
|
1651
|
+
const alignClass = getAlignmentClasses(align);
|
|
1652
|
+
// If layout is constrained, use container
|
|
1653
|
+
if (layout?.type === 'constrained') {
|
|
1654
|
+
return align === 'full' ? 'w-full' : 'container';
|
|
1655
|
+
}
|
|
1656
|
+
return alignClass || 'container';
|
|
1657
|
+
}
|
|
1658
|
+
/**
|
|
1659
|
+
* Get spacing classes for sections
|
|
1660
|
+
*/
|
|
1661
|
+
function getSectionSpacingClasses() {
|
|
1662
|
+
return 'py-16 md:py-24';
|
|
1663
|
+
}
|
|
1664
|
+
/**
|
|
1665
|
+
* Get content spacing classes
|
|
1666
|
+
*/
|
|
1667
|
+
function getContentSpacingClasses() {
|
|
1668
|
+
return 'space-y-6';
|
|
1669
|
+
}
|
|
1670
|
+
/**
|
|
1671
|
+
* Build className string from multiple class sources
|
|
1672
|
+
*/
|
|
1673
|
+
function buildClassName(...classes) {
|
|
1674
|
+
return classes
|
|
1675
|
+
.filter((cls) => Boolean(cls && cls.trim()))
|
|
1676
|
+
.join(' ')
|
|
1677
|
+
.trim();
|
|
1678
|
+
}
|
|
1679
|
+
|
|
1680
|
+
/**
|
|
1681
|
+
* Cloudflare Images URL helpers for wparser package
|
|
1682
|
+
* Formats Cloudflare image URLs with variants for optimal performance
|
|
1683
|
+
*/
|
|
1684
|
+
/**
|
|
1685
|
+
* Check if a URL is a Cloudflare Images URL
|
|
1686
|
+
*/
|
|
1687
|
+
const isCloudflareImageUrl = (url) => {
|
|
1688
|
+
if (!url)
|
|
1689
|
+
return false;
|
|
1690
|
+
try {
|
|
1691
|
+
const u = new URL(url);
|
|
1692
|
+
return u.hostname.toLowerCase().includes('imagedelivery.net');
|
|
1693
|
+
}
|
|
1694
|
+
catch {
|
|
1695
|
+
return false;
|
|
1696
|
+
}
|
|
1697
|
+
};
|
|
1698
|
+
/**
|
|
1699
|
+
* Append Cloudflare Images variant to the base URL if not already present.
|
|
1700
|
+
* Example output: https://imagedelivery.net/<account>/<id>/w=1024,h=600
|
|
1701
|
+
*/
|
|
1702
|
+
const getCloudflareVariantUrl = (url, options) => {
|
|
1703
|
+
if (!isCloudflareImageUrl(url))
|
|
1704
|
+
return url;
|
|
1705
|
+
// If a transform already exists, return as-is
|
|
1706
|
+
if (/\/w=\d+/.test(url) || /\/(public|thumbnail|banner|avatar)/.test(url)) {
|
|
1707
|
+
return url;
|
|
1708
|
+
}
|
|
1709
|
+
const { width, height } = options;
|
|
1710
|
+
const hasTrailingSlash = url.endsWith('/');
|
|
1711
|
+
const base = hasTrailingSlash ? url.slice(0, -1) : url;
|
|
1712
|
+
const variant = `w=${Math.max(1, Math.floor(width))}` + (height ? `,h=${Math.max(1, Math.floor(height))}` : '');
|
|
1713
|
+
return `${base}/${variant}`;
|
|
1714
|
+
};
|
|
1715
|
+
|
|
1509
1716
|
const Paragraph = ({ block, context }) => {
|
|
1510
|
-
const content =
|
|
1717
|
+
const content = getBlockTextContent(block);
|
|
1718
|
+
const attrs = block.attributes || {};
|
|
1719
|
+
const textAlign = getTextAlignClasses(attrs['align']);
|
|
1511
1720
|
// Check if content contains shortcodes
|
|
1512
1721
|
const hasShortcodes = /\[(\w+)/.test(content);
|
|
1513
1722
|
if (hasShortcodes && context.registry.shortcodes) {
|
|
1514
1723
|
const parts = renderTextWithShortcodes(content, context.registry);
|
|
1515
|
-
return jsxRuntimeExports.jsx("p", { className:
|
|
1724
|
+
return jsxRuntimeExports.jsx("p", { className: buildClassName('text-gray-700', textAlign), children: parts });
|
|
1516
1725
|
}
|
|
1517
|
-
return jsxRuntimeExports.jsx("p", { className:
|
|
1726
|
+
return jsxRuntimeExports.jsx("p", { className: buildClassName('text-gray-700', textAlign), children: content });
|
|
1518
1727
|
};
|
|
1519
1728
|
const Heading = ({ block, children }) => {
|
|
1520
|
-
const
|
|
1521
|
-
const
|
|
1729
|
+
const attrs = block.attributes || {};
|
|
1730
|
+
const { level = 2 } = attrs;
|
|
1731
|
+
const content = getBlockTextContent(block);
|
|
1732
|
+
const textAlign = getTextAlignClasses(attrs['textAlign']);
|
|
1733
|
+
const fontSize = getFontSizeClasses(attrs['fontSize']);
|
|
1522
1734
|
const Tag = `h${Math.min(Math.max(Number(level) || 2, 1), 6)}`;
|
|
1523
|
-
|
|
1735
|
+
// Default heading sizes if fontSize not specified
|
|
1736
|
+
const sizeClass = fontSize || (level === 1 ? 'text-4xl' : level === 2 ? 'text-3xl' : level === 3 ? 'text-2xl' : 'text-xl');
|
|
1737
|
+
return (jsxRuntimeExports.jsx(Tag, { className: buildClassName('font-bold text-gray-900', sizeClass, textAlign), children: children ?? content }));
|
|
1524
1738
|
};
|
|
1525
1739
|
const Image = ({ block }) => {
|
|
1526
|
-
const
|
|
1527
|
-
if (!url)
|
|
1740
|
+
const imageAttrs = getImageAttributes(block);
|
|
1741
|
+
if (!imageAttrs.url)
|
|
1528
1742
|
return null;
|
|
1529
|
-
|
|
1743
|
+
// Use Cloudflare variant URL if it's a Cloudflare image
|
|
1744
|
+
let imageUrl = imageAttrs.url;
|
|
1745
|
+
if (isCloudflareImageUrl(imageUrl)) {
|
|
1746
|
+
const width = imageAttrs.width || 1024;
|
|
1747
|
+
const height = imageAttrs.height;
|
|
1748
|
+
imageUrl = getCloudflareVariantUrl(imageUrl, { width, height });
|
|
1749
|
+
}
|
|
1750
|
+
return (jsxRuntimeExports.jsx("img", { src: imageUrl, alt: imageAttrs.alt, width: imageAttrs.width, height: imageAttrs.height, className: "w-full h-auto object-cover rounded-lg", loading: "lazy" }));
|
|
1530
1751
|
};
|
|
1531
1752
|
const List = ({ block, children }) => {
|
|
1532
|
-
const
|
|
1753
|
+
const attrs = block.attributes || {};
|
|
1754
|
+
const { ordered } = attrs;
|
|
1533
1755
|
const Tag = ordered ? 'ol' : 'ul';
|
|
1534
|
-
return React.createElement(Tag, { className: 'list-disc pl-6 space-y-
|
|
1756
|
+
return React.createElement(Tag, { className: 'list-disc pl-6 space-y-2 text-gray-700' }, children);
|
|
1535
1757
|
};
|
|
1536
1758
|
const ListItem = ({ children }) => {
|
|
1537
|
-
return jsxRuntimeExports.jsx("li", { children: children });
|
|
1759
|
+
return jsxRuntimeExports.jsx("li", { className: "text-gray-700", children: children });
|
|
1538
1760
|
};
|
|
1539
|
-
const Group = ({ children }) => {
|
|
1540
|
-
|
|
1761
|
+
const Group = ({ block, children }) => {
|
|
1762
|
+
const attrs = block.attributes || {};
|
|
1763
|
+
const align = attrs['align'];
|
|
1764
|
+
const layout = attrs['layout'];
|
|
1765
|
+
// Determine if this is a section-level group (has alignment) or content-level
|
|
1766
|
+
const isSection = align === 'full' || align === 'wide';
|
|
1767
|
+
const containerClass = getContainerClasses(align, layout);
|
|
1768
|
+
const spacingClass = isSection ? getSectionSpacingClasses() : getContentSpacingClasses();
|
|
1769
|
+
return (jsxRuntimeExports.jsx("div", { className: buildClassName(containerClass, spacingClass), children: children }));
|
|
1541
1770
|
};
|
|
1542
|
-
const Columns = ({ children }) => {
|
|
1543
|
-
|
|
1771
|
+
const Columns = ({ block, children }) => {
|
|
1772
|
+
const attrs = block.attributes || {};
|
|
1773
|
+
const align = attrs['align'];
|
|
1774
|
+
const alignClass = getAlignmentClasses(align);
|
|
1775
|
+
return (jsxRuntimeExports.jsx("div", { className: buildClassName('grid grid-cols-1 md:grid-cols-2 gap-6 lg:gap-12', alignClass), children: children }));
|
|
1544
1776
|
};
|
|
1545
|
-
const Column = ({ children }) => {
|
|
1546
|
-
|
|
1777
|
+
const Column = ({ block, children }) => {
|
|
1778
|
+
const attrs = block.attributes || {};
|
|
1779
|
+
const width = attrs['width'];
|
|
1780
|
+
// Handle column width (e.g., "50%" becomes flex-basis)
|
|
1781
|
+
const style = width ? { flexBasis: width } : undefined;
|
|
1782
|
+
return (jsxRuntimeExports.jsx("div", { className: "space-y-4", style: style, children: children }));
|
|
1547
1783
|
};
|
|
1548
1784
|
const Separator = () => jsxRuntimeExports.jsx("hr", { className: "border-gray-200 my-8" });
|
|
1549
1785
|
const ButtonBlock = ({ block }) => {
|
|
1550
|
-
const
|
|
1551
|
-
|
|
1786
|
+
const attrs = block.attributes || {};
|
|
1787
|
+
const url = attrs['url'];
|
|
1788
|
+
const text = attrs['text'];
|
|
1789
|
+
attrs['linkDestination'];
|
|
1790
|
+
if (!url && !text)
|
|
1552
1791
|
return null;
|
|
1553
|
-
|
|
1792
|
+
const buttonText = text || getBlockTextContent(block) || 'Learn more';
|
|
1793
|
+
// Handle internal vs external links
|
|
1794
|
+
const isExternal = url && (url.startsWith('http://') || url.startsWith('https://'));
|
|
1795
|
+
const linkProps = isExternal ? { target: '_blank', rel: 'noopener noreferrer' } : {};
|
|
1796
|
+
return (jsxRuntimeExports.jsx("a", { href: url || '#', className: "inline-flex items-center justify-center rounded-md bg-primary px-6 py-3 text-white font-medium hover:bg-primary/90 transition-colors", ...linkProps, children: buttonText }));
|
|
1797
|
+
};
|
|
1798
|
+
const Cover = ({ block, children }) => {
|
|
1799
|
+
const attrs = block.attributes || {};
|
|
1800
|
+
const { url, id, backgroundImage, overlayColor, dimRatio = 0, align = 'full', minHeight, minHeightUnit = 'vh', hasParallax, } = attrs;
|
|
1801
|
+
// Get background image URL from various possible sources
|
|
1802
|
+
let bgImageUrl = url || backgroundImage || (typeof backgroundImage === 'object' && backgroundImage?.url);
|
|
1803
|
+
// If we have an image ID, try to get Cloudflare URL from media data
|
|
1804
|
+
// For now, use the URL as-is (should already be Cloudflare if processed)
|
|
1805
|
+
if (bgImageUrl && isCloudflareImageUrl(bgImageUrl)) {
|
|
1806
|
+
// Use full width for cover images
|
|
1807
|
+
bgImageUrl = getCloudflareVariantUrl(bgImageUrl, { width: 1920 });
|
|
1808
|
+
}
|
|
1809
|
+
// Build alignment classes
|
|
1810
|
+
const alignClass = getAlignmentClasses(align);
|
|
1811
|
+
// Build style object
|
|
1812
|
+
const style = {};
|
|
1813
|
+
if (minHeight) {
|
|
1814
|
+
const minHeightValue = typeof minHeight === 'number' ? minHeight : parseFloat(String(minHeight));
|
|
1815
|
+
style.minHeight = minHeightUnit === 'vh' ? `${minHeightValue}vh` : `${minHeightValue}px`;
|
|
1816
|
+
}
|
|
1817
|
+
if (bgImageUrl) {
|
|
1818
|
+
style.backgroundImage = `url(${bgImageUrl})`;
|
|
1819
|
+
style.backgroundSize = 'cover';
|
|
1820
|
+
style.backgroundPosition = 'center';
|
|
1821
|
+
if (hasParallax) {
|
|
1822
|
+
style.backgroundAttachment = 'fixed';
|
|
1823
|
+
}
|
|
1824
|
+
}
|
|
1825
|
+
// Calculate overlay opacity
|
|
1826
|
+
const overlayOpacity = typeof dimRatio === 'number' ? dimRatio / 100 : 0;
|
|
1827
|
+
return (jsxRuntimeExports.jsxs("div", { className: buildClassName('relative', alignClass), style: style, children: [overlayOpacity > 0 && (jsxRuntimeExports.jsx("span", { className: "absolute inset-0", style: {
|
|
1828
|
+
backgroundColor: overlayColor || '#000000',
|
|
1829
|
+
opacity: overlayOpacity,
|
|
1830
|
+
}, "aria-hidden": "true" })), jsxRuntimeExports.jsx("div", { className: "relative z-10 container", children: children })] }));
|
|
1831
|
+
};
|
|
1832
|
+
const MediaText = ({ block, children, context }) => {
|
|
1833
|
+
const attrs = block.attributes || {};
|
|
1834
|
+
const { mediaPosition = 'left', verticalAlignment = 'center', imageFill = false, align = 'wide', } = attrs;
|
|
1835
|
+
// Access innerBlocks to identify media vs content
|
|
1836
|
+
const innerBlocks = block.innerBlocks || [];
|
|
1837
|
+
// Find media block (image or video)
|
|
1838
|
+
const mediaBlockIndex = innerBlocks.findIndex((b) => b.name === 'core/image' || b.name === 'core/video');
|
|
1839
|
+
// Render children - media-text typically has media as first child, then content
|
|
1840
|
+
const childrenArray = React.Children.toArray(children);
|
|
1841
|
+
const mediaElement = mediaBlockIndex >= 0 && childrenArray[mediaBlockIndex]
|
|
1842
|
+
? childrenArray[mediaBlockIndex]
|
|
1843
|
+
: null;
|
|
1844
|
+
// Content is all other children
|
|
1845
|
+
const contentElements = childrenArray.filter((_, index) => index !== mediaBlockIndex);
|
|
1846
|
+
// Build alignment classes
|
|
1847
|
+
const alignClass = getAlignmentClasses(align) || 'max-w-7xl mx-auto';
|
|
1848
|
+
// Vertical alignment classes
|
|
1849
|
+
const verticalAlignClass = verticalAlignment === 'top' ? 'items-start' :
|
|
1850
|
+
verticalAlignment === 'bottom' ? 'items-end' :
|
|
1851
|
+
'items-center';
|
|
1852
|
+
// Stack on mobile
|
|
1853
|
+
const stackClass = 'flex-col md:flex-row';
|
|
1854
|
+
// Media position determines order
|
|
1855
|
+
const isMediaRight = mediaPosition === 'right';
|
|
1856
|
+
return (jsxRuntimeExports.jsx("div", { className: buildClassName(alignClass, 'px-4'), children: jsxRuntimeExports.jsxs("div", { className: buildClassName('flex', stackClass, verticalAlignClass, 'gap-6 lg:gap-12'), children: [jsxRuntimeExports.jsx("div", { className: buildClassName(isMediaRight ? 'order-2' : 'order-1', imageFill ? 'w-full md:w-1/2' : 'flex-shrink-0'), children: mediaElement || jsxRuntimeExports.jsx("div", { className: "bg-gray-200 h-64 rounded-lg" }) }), jsxRuntimeExports.jsx("div", { className: buildClassName(isMediaRight ? 'order-1' : 'order-2', imageFill ? 'w-full md:w-1/2' : 'flex-1', 'space-y-4'), children: contentElements.length > 0 ? contentElements : children })] }) }));
|
|
1554
1857
|
};
|
|
1555
1858
|
const Fallback = ({ block, children }) => {
|
|
1556
1859
|
// Minimal fallback; do not render innerHTML directly in v1 for safety
|
|
@@ -1568,13 +1871,25 @@ function createDefaultRegistry() {
|
|
|
1568
1871
|
'core/column': Column,
|
|
1569
1872
|
'core/separator': Separator,
|
|
1570
1873
|
'core/button': ButtonBlock,
|
|
1571
|
-
'core/buttons': ({ children }) =>
|
|
1874
|
+
'core/buttons': ({ block, children }) => {
|
|
1875
|
+
const attrs = block.attributes || {};
|
|
1876
|
+
const layout = attrs['layout'];
|
|
1877
|
+
const justifyContent = layout?.justifyContent || 'left';
|
|
1878
|
+
const justifyClass = justifyContent === 'center' ? 'justify-center' :
|
|
1879
|
+
justifyContent === 'right' ? 'justify-end' :
|
|
1880
|
+
'justify-start';
|
|
1881
|
+
return jsxRuntimeExports.jsx("div", { className: buildClassName('flex flex-wrap gap-3', justifyClass), children: children });
|
|
1882
|
+
},
|
|
1572
1883
|
'core/quote': ({ children }) => jsxRuntimeExports.jsx("blockquote", { className: "border-l-4 pl-4 italic", children: children }),
|
|
1573
1884
|
'core/code': ({ block }) => (jsxRuntimeExports.jsx("pre", { className: "bg-gray-100 p-3 rounded text-sm overflow-auto", children: jsxRuntimeExports.jsx("code", { children: getString(block) }) })),
|
|
1574
1885
|
'core/preformatted': ({ block }) => jsxRuntimeExports.jsx("pre", { children: getString(block) }),
|
|
1575
1886
|
'core/table': ({ children }) => jsxRuntimeExports.jsx("div", { className: "overflow-x-auto", children: jsxRuntimeExports.jsx("table", { className: "table-auto w-full", children: children }) }),
|
|
1576
1887
|
'core/table-row': ({ children }) => jsxRuntimeExports.jsx("tr", { children: children }),
|
|
1577
1888
|
'core/table-cell': ({ children }) => jsxRuntimeExports.jsx("td", { className: "border px-3 py-2", children: children }),
|
|
1889
|
+
// Cover block - hero sections with background images
|
|
1890
|
+
'core/cover': Cover,
|
|
1891
|
+
// Media & Text block - side-by-side media and content
|
|
1892
|
+
'core/media-text': MediaText,
|
|
1578
1893
|
// HTML block - render innerHTML as-is
|
|
1579
1894
|
// Note: Shortcodes in HTML blocks are not parsed (they would need to be in text content)
|
|
1580
1895
|
'core/html': ({ block }) => {
|
|
@@ -1588,12 +1903,9 @@ function createDefaultRegistry() {
|
|
|
1588
1903
|
fallback: Fallback,
|
|
1589
1904
|
};
|
|
1590
1905
|
}
|
|
1906
|
+
// Legacy function for backward compatibility - use getBlockTextContent instead
|
|
1591
1907
|
function getString(block) {
|
|
1592
|
-
|
|
1593
|
-
const content = attrs['content'];
|
|
1594
|
-
const text = attrs['text'];
|
|
1595
|
-
const value = (typeof content === 'string' ? content : typeof text === 'string' ? text : block.innerHTML || '');
|
|
1596
|
-
return String(value);
|
|
1908
|
+
return getBlockTextContent(block);
|
|
1597
1909
|
}
|
|
1598
1910
|
|
|
1599
1911
|
const WPContent = ({ blocks, registry, className }) => {
|
|
@@ -1679,8 +1991,21 @@ class WPErrorBoundary extends React.Component {
|
|
|
1679
1991
|
exports.WPContent = WPContent;
|
|
1680
1992
|
exports.WPErrorBoundary = WPErrorBoundary;
|
|
1681
1993
|
exports.WPPage = WPPage;
|
|
1994
|
+
exports.buildClassName = buildClassName;
|
|
1682
1995
|
exports.createDefaultRegistry = createDefaultRegistry;
|
|
1996
|
+
exports.extractTextFromHTML = extractTextFromHTML;
|
|
1683
1997
|
exports.findShortcodes = findShortcodes;
|
|
1998
|
+
exports.getAlignmentClasses = getAlignmentClasses;
|
|
1999
|
+
exports.getBlockTextContent = getBlockTextContent;
|
|
2000
|
+
exports.getCloudflareVariantUrl = getCloudflareVariantUrl;
|
|
2001
|
+
exports.getContainerClasses = getContainerClasses;
|
|
2002
|
+
exports.getContentSpacingClasses = getContentSpacingClasses;
|
|
2003
|
+
exports.getFontSizeClasses = getFontSizeClasses;
|
|
2004
|
+
exports.getImageAttributes = getImageAttributes;
|
|
2005
|
+
exports.getImageUrl = getImageUrl;
|
|
2006
|
+
exports.getSectionSpacingClasses = getSectionSpacingClasses;
|
|
2007
|
+
exports.getTextAlignClasses = getTextAlignClasses;
|
|
2008
|
+
exports.isCloudflareImageUrl = isCloudflareImageUrl;
|
|
1684
2009
|
exports.parseGutenbergBlocks = parseGutenbergBlocks;
|
|
1685
2010
|
exports.parseShortcodeAttrs = parseShortcodeAttrs;
|
|
1686
2011
|
exports.renderNodes = renderNodes;
|