@marvalt/wparser 0.1.5 → 0.1.7

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.
@@ -0,0 +1,30 @@
1
+ import React from 'react';
2
+ import type { WordPressBlock } from '../types';
3
+ export interface SectionWrapperProps {
4
+ children: React.ReactNode;
5
+ /** Background color variant */
6
+ background?: 'light' | 'dark' | 'transparent';
7
+ /** Vertical spacing between sections */
8
+ spacing?: 'none' | 'small' | 'medium' | 'large';
9
+ /** Container width */
10
+ container?: 'full' | 'wide' | 'contained';
11
+ /** Additional CSS classes */
12
+ className?: string;
13
+ /** Optional block reference for extracting additional props */
14
+ block?: WordPressBlock;
15
+ }
16
+ /**
17
+ * Generic section wrapper component for consistent spacing and layout
18
+ *
19
+ * Usage in component mappings:
20
+ * ```ts
21
+ * {
22
+ * pattern: { name: 'core/cover' },
23
+ * component: HeroSection,
24
+ * wrapper: SectionWrapper,
25
+ * extractProps: (block) => ({ ... })
26
+ * }
27
+ * ```
28
+ */
29
+ export declare const SectionWrapper: React.FC<SectionWrapperProps>;
30
+ //# sourceMappingURL=SectionWrapper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SectionWrapper.d.ts","sourceRoot":"","sources":["../../src/components/SectionWrapper.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAG/C,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,+BAA+B;IAC/B,UAAU,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,aAAa,CAAC;IAC9C,wCAAwC;IACxC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;IAChD,sBAAsB;IACtB,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,WAAW,CAAC;IAC1C,6BAA6B;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+DAA+D;IAC/D,KAAK,CAAC,EAAE,cAAc,CAAC;CACxB;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CAqDxD,CAAC"}
package/dist/index.cjs CHANGED
@@ -1517,7 +1517,7 @@ function extractTextFromHTML(html) {
1517
1517
  if (!html)
1518
1518
  return '';
1519
1519
  // Remove HTML tags and decode entities
1520
- const text = html
1520
+ let text = html
1521
1521
  .replace(/<[^>]*>/g, '') // Remove HTML tags
1522
1522
  .replace(/&nbsp;/g, ' ') // Replace &nbsp; with space
1523
1523
  .replace(/&#8217;/g, "'") // Replace apostrophe entity
@@ -1528,7 +1528,11 @@ function extractTextFromHTML(html) {
1528
1528
  .replace(/&lt;/g, '<') // Replace &lt;
1529
1529
  .replace(/&gt;/g, '>') // Replace &gt;
1530
1530
  .replace(/&quot;/g, '"') // Replace &quot;
1531
+ .replace(/&#8211;/g, '–') // Replace en dash
1532
+ .replace(/&#8212;/g, '—') // Replace em dash
1531
1533
  .trim();
1534
+ // Clean up extra whitespace
1535
+ text = text.replace(/\s+/g, ' ');
1532
1536
  return text;
1533
1537
  }
1534
1538
  /**
@@ -1550,11 +1554,12 @@ function getBlockTextContent(block) {
1550
1554
  /**
1551
1555
  * Extract image URL from block attributes
1552
1556
  * Checks for Cloudflare URLs first, then falls back to regular URLs
1557
+ * Also extracts from innerHTML if needed
1553
1558
  */
1554
1559
  function getImageUrl(block) {
1555
1560
  const attrs = block.attributes || {};
1556
1561
  // Check various possible URL attributes
1557
- const url = attrs['url'] ||
1562
+ let url = attrs['url'] ||
1558
1563
  attrs['src'] ||
1559
1564
  attrs['imageUrl'] ||
1560
1565
  attrs['mediaUrl'] ||
@@ -1564,10 +1569,16 @@ function getImageUrl(block) {
1564
1569
  }
1565
1570
  // Try to extract from innerHTML if it's an img tag
1566
1571
  if (block.innerHTML) {
1567
- const imgMatch = block.innerHTML.match(/src=["']([^"']+)["']/);
1572
+ // Try img src first
1573
+ const imgMatch = block.innerHTML.match(/<img[^>]+src=["']([^"']+)["']/i);
1568
1574
  if (imgMatch && imgMatch[1]) {
1569
1575
  return imgMatch[1];
1570
1576
  }
1577
+ // Try background-image in style attribute
1578
+ const bgMatch = block.innerHTML.match(/background-image:\s*url\(["']?([^"')]+)["']?\)/i);
1579
+ if (bgMatch && bgMatch[1]) {
1580
+ return bgMatch[1];
1581
+ }
1571
1582
  }
1572
1583
  return null;
1573
1584
  }
@@ -1800,8 +1811,22 @@ const Cover = ({ block, children }) => {
1800
1811
  const { url, id, backgroundImage, overlayColor, dimRatio = 0, align = 'full', minHeight, minHeightUnit = 'vh', hasParallax, } = attrs;
1801
1812
  // Get background image URL from various possible sources
1802
1813
  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)
1814
+ // If not found in attributes, try to extract from innerHTML
1815
+ if (!bgImageUrl && block.innerHTML) {
1816
+ // Try to extract img src from innerHTML
1817
+ const imgMatch = block.innerHTML.match(/<img[^>]+src=["']([^"']+)["']/i);
1818
+ if (imgMatch && imgMatch[1]) {
1819
+ bgImageUrl = imgMatch[1];
1820
+ }
1821
+ // Try background-image in style attribute
1822
+ if (!bgImageUrl) {
1823
+ const bgMatch = block.innerHTML.match(/background-image:\s*url\(["']?([^"')]+)["']?\)/i);
1824
+ if (bgMatch && bgMatch[1]) {
1825
+ bgImageUrl = bgMatch[1];
1826
+ }
1827
+ }
1828
+ }
1829
+ // Convert to Cloudflare URL if it's a Cloudflare image, otherwise use as-is
1805
1830
  if (bgImageUrl && isCloudflareImageUrl(bgImageUrl)) {
1806
1831
  // Use full width for cover images
1807
1832
  bgImageUrl = getCloudflareVariantUrl(bgImageUrl, { width: 1920 });
@@ -1824,10 +1849,10 @@ const Cover = ({ block, children }) => {
1824
1849
  }
1825
1850
  // Calculate overlay opacity
1826
1851
  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',
1852
+ return (jsxRuntimeExports.jsxs("div", { className: buildClassName('relative w-full', alignClass), style: style, children: [overlayOpacity > 0 && (jsxRuntimeExports.jsx("span", { className: "absolute inset-0 z-0", style: {
1853
+ backgroundColor: overlayColor === 'contrast' ? '#000000' : (overlayColor || '#000000'),
1829
1854
  opacity: overlayOpacity,
1830
- }, "aria-hidden": "true" })), jsxRuntimeExports.jsx("div", { className: "relative z-10 container", children: children })] }));
1855
+ }, "aria-hidden": "true" })), jsxRuntimeExports.jsx("div", { className: buildClassName('relative z-10', align === 'full' ? 'w-full' : 'container mx-auto px-4'), children: children })] }));
1831
1856
  };
1832
1857
  const MediaText = ({ block, children, context }) => {
1833
1858
  const attrs = block.attributes || {};
@@ -1908,6 +1933,138 @@ function getString(block) {
1908
1933
  return getBlockTextContent(block);
1909
1934
  }
1910
1935
 
1936
+ /**
1937
+ * Check if a block matches a pattern
1938
+ */
1939
+ function matchesPattern(block, pattern) {
1940
+ // Check block name
1941
+ if (block.name !== pattern.name) {
1942
+ return false;
1943
+ }
1944
+ // Check attributes if specified
1945
+ if (pattern.attributes) {
1946
+ const blockAttrs = block.attributes || {};
1947
+ for (const [key, value] of Object.entries(pattern.attributes)) {
1948
+ if (blockAttrs[key] !== value) {
1949
+ return false;
1950
+ }
1951
+ }
1952
+ }
1953
+ // Check innerBlocks patterns if specified
1954
+ if (pattern.innerBlocks && pattern.innerBlocks.length > 0) {
1955
+ const blockInnerBlocks = block.innerBlocks || [];
1956
+ // If pattern specifies innerBlocks, check if block has matching innerBlocks
1957
+ for (const innerPattern of pattern.innerBlocks) {
1958
+ // Find at least one matching innerBlock
1959
+ const hasMatch = blockInnerBlocks.some(innerBlock => matchesPattern(innerBlock, innerPattern));
1960
+ if (!hasMatch) {
1961
+ return false;
1962
+ }
1963
+ }
1964
+ }
1965
+ return true;
1966
+ }
1967
+ /**
1968
+ * Find the best matching component mapping for a block
1969
+ * Returns the mapping with highest priority that matches, or null
1970
+ */
1971
+ function findMatchingMapping(block, mappings) {
1972
+ // Sort by priority (higher first), then by order in array
1973
+ const sortedMappings = [...mappings].sort((a, b) => {
1974
+ const priorityA = a.priority ?? 0;
1975
+ const priorityB = b.priority ?? 0;
1976
+ if (priorityA !== priorityB) {
1977
+ return priorityB - priorityA; // Higher priority first
1978
+ }
1979
+ return 0; // Keep original order for same priority
1980
+ });
1981
+ // Find first matching mapping
1982
+ for (const mapping of sortedMappings) {
1983
+ if (matchesPattern(block, mapping.pattern)) {
1984
+ return mapping;
1985
+ }
1986
+ }
1987
+ return null;
1988
+ }
1989
+
1990
+ /**
1991
+ * Create an enhanced registry that supports pattern-based component mapping
1992
+ *
1993
+ * This combines the default registry (for fallback) with app-specific component mappings.
1994
+ * When a block matches a pattern, it uses the mapped component. Otherwise, it falls back
1995
+ * to the default renderer.
1996
+ *
1997
+ * @param mappings - Array of component mappings with patterns
1998
+ * @param baseRegistry - Optional base registry (defaults to createDefaultRegistry())
1999
+ * @returns Enhanced registry with pattern matching capabilities
2000
+ *
2001
+ * @example
2002
+ * ```ts
2003
+ * const mappings: ComponentMapping[] = [
2004
+ * {
2005
+ * pattern: { name: 'core/cover' },
2006
+ * component: HomeHeroSection,
2007
+ * extractProps: (block) => ({
2008
+ * backgroundImage: extractBackgroundImage(block),
2009
+ * title: extractTitle(block),
2010
+ * }),
2011
+ * wrapper: SectionWrapper,
2012
+ * },
2013
+ * ];
2014
+ *
2015
+ * const registry = createEnhancedRegistry(mappings);
2016
+ * ```
2017
+ */
2018
+ function createEnhancedRegistry(mappings = [], baseRegistry) {
2019
+ const base = baseRegistry || createDefaultRegistry();
2020
+ // Create enhanced renderers that check patterns first
2021
+ const enhancedRenderers = {
2022
+ ...base.renderers,
2023
+ };
2024
+ // Override renderers for blocks that have mappings
2025
+ // We need to check patterns at render time, so we create a wrapper renderer
2026
+ const createPatternRenderer = (blockName) => {
2027
+ return (props) => {
2028
+ const { block, context } = props;
2029
+ // Find matching mapping
2030
+ const mapping = findMatchingMapping(block, mappings);
2031
+ if (mapping) {
2032
+ // Extract props from block
2033
+ const componentProps = mapping.extractProps(block, context);
2034
+ // Render component
2035
+ const Component = mapping.component;
2036
+ const content = jsxRuntimeExports.jsx(Component, { ...componentProps });
2037
+ // Wrap with wrapper if provided
2038
+ if (mapping.wrapper) {
2039
+ const Wrapper = mapping.wrapper;
2040
+ return jsxRuntimeExports.jsx(Wrapper, { block: block, children: content });
2041
+ }
2042
+ return content;
2043
+ }
2044
+ // Fall back to default renderer
2045
+ const defaultRenderer = base.renderers[blockName] || base.fallback;
2046
+ return defaultRenderer(props);
2047
+ };
2048
+ };
2049
+ // For each mapping, override the renderer for that block name
2050
+ for (const mapping of mappings) {
2051
+ const blockName = mapping.pattern.name;
2052
+ if (blockName) {
2053
+ enhancedRenderers[blockName] = createPatternRenderer(blockName);
2054
+ }
2055
+ }
2056
+ // Create matchBlock function
2057
+ const matchBlock = (block) => {
2058
+ return findMatchingMapping(block, mappings);
2059
+ };
2060
+ return {
2061
+ ...base,
2062
+ renderers: enhancedRenderers,
2063
+ mappings,
2064
+ matchBlock,
2065
+ };
2066
+ }
2067
+
1911
2068
  const WPContent = ({ blocks, registry, className }) => {
1912
2069
  if (!Array.isArray(blocks)) {
1913
2070
  if (process.env.NODE_ENV !== 'production') {
@@ -1941,7 +2098,7 @@ const WPPage = ({ page, registry, className }) => {
1941
2098
  }
1942
2099
  const hasHeroShortcode = React.useMemo(() => detectHeroShortcode(page.blocks), [page.blocks]);
1943
2100
  const featured = getFeaturedImage(page);
1944
- return (jsxRuntimeExports.jsxs("article", { className: className, children: [!hasHeroShortcode && featured && (jsxRuntimeExports.jsx(HeroFromFeatured, { featured: featured, title: page.title?.rendered })), jsxRuntimeExports.jsxs("div", { className: "container mx-auto px-4 py-8 prose max-w-none", children: [jsxRuntimeExports.jsx("header", { className: "mb-8", children: page.title?.rendered && (jsxRuntimeExports.jsx("h1", { className: "text-3xl font-bold", children: page.title.rendered })) }), jsxRuntimeExports.jsx(WPContent, { blocks: page.blocks, registry: registry })] })] }));
2101
+ return (jsxRuntimeExports.jsxs("article", { className: className, children: [!hasHeroShortcode && featured && (jsxRuntimeExports.jsx(HeroFromFeatured, { featured: featured, title: page.title?.rendered })), jsxRuntimeExports.jsx(WPContent, { blocks: page.blocks, registry: registry })] }));
1945
2102
  };
1946
2103
  function detectHeroShortcode(blocks) {
1947
2104
  for (const block of blocks) {
@@ -1988,12 +2145,279 @@ class WPErrorBoundary extends React.Component {
1988
2145
  }
1989
2146
  }
1990
2147
 
2148
+ /**
2149
+ * Extract background image URL from a block
2150
+ * Checks various possible sources: url, backgroundImage, innerHTML
2151
+ */
2152
+ function extractBackgroundImage(block) {
2153
+ const attrs = block.attributes || {};
2154
+ // Try various attribute keys
2155
+ let url = attrs['url'] ||
2156
+ attrs['backgroundImage'] ||
2157
+ (typeof attrs['backgroundImage'] === 'object' && attrs['backgroundImage']?.url);
2158
+ if (typeof url === 'string' && url.trim()) {
2159
+ return url.trim();
2160
+ }
2161
+ // Try to extract from innerHTML if not found in attributes
2162
+ if (block.innerHTML) {
2163
+ // Try img src from innerHTML
2164
+ const imgMatch = block.innerHTML.match(/<img[^>]+src=["']([^"']+)["']/i);
2165
+ if (imgMatch && imgMatch[1]) {
2166
+ return imgMatch[1];
2167
+ }
2168
+ // Try background-image in style attribute
2169
+ const bgMatch = block.innerHTML.match(/background-image:\s*url\(["']?([^"')]+)["']?\)/i);
2170
+ if (bgMatch && bgMatch[1]) {
2171
+ return bgMatch[1];
2172
+ }
2173
+ }
2174
+ return null;
2175
+ }
2176
+ /**
2177
+ * Extract image URL from a block
2178
+ * Returns Cloudflare URL if available, otherwise WordPress URL
2179
+ */
2180
+ function extractImageUrl(block) {
2181
+ return getImageUrl(block);
2182
+ }
2183
+ /**
2184
+ * Extract image attributes (url, alt, width, height)
2185
+ */
2186
+ function extractImageAttributes(block) {
2187
+ return getImageAttributes(block);
2188
+ }
2189
+ /**
2190
+ * Extract title/heading text from a block
2191
+ */
2192
+ function extractTitle(block) {
2193
+ const attrs = block.attributes || {};
2194
+ const title = attrs['title'] || attrs['content'] || getBlockTextContent(block);
2195
+ return typeof title === 'string' ? title.trim() : null;
2196
+ }
2197
+ /**
2198
+ * Extract content/text from a block
2199
+ * Returns React node for rendering
2200
+ */
2201
+ function extractContent(block, context) {
2202
+ const text = getBlockTextContent(block);
2203
+ return text || null;
2204
+ }
2205
+ /**
2206
+ * Extract media position from media-text block
2207
+ */
2208
+ function extractMediaPosition(block) {
2209
+ const attrs = block.attributes || {};
2210
+ const position = attrs['mediaPosition'] || 'left';
2211
+ return position === 'right' ? 'right' : 'left';
2212
+ }
2213
+ /**
2214
+ * Extract vertical alignment from block
2215
+ */
2216
+ function extractVerticalAlignment(block) {
2217
+ const attrs = block.attributes || {};
2218
+ const alignment = attrs['verticalAlignment'] || 'center';
2219
+ if (alignment === 'top' || alignment === 'bottom') {
2220
+ return alignment;
2221
+ }
2222
+ return 'center';
2223
+ }
2224
+ /**
2225
+ * Extract alignment (full, wide, contained) from block
2226
+ */
2227
+ function extractAlignment(block) {
2228
+ const attrs = block.attributes || {};
2229
+ const align = attrs['align'];
2230
+ if (align === 'full' || align === 'wide') {
2231
+ return align;
2232
+ }
2233
+ return 'contained';
2234
+ }
2235
+ /**
2236
+ * Extract overlay color from cover block
2237
+ */
2238
+ function extractOverlayColor(block) {
2239
+ const attrs = block.attributes || {};
2240
+ const overlayColor = attrs['overlayColor'];
2241
+ if (typeof overlayColor === 'string') {
2242
+ return overlayColor;
2243
+ }
2244
+ return null;
2245
+ }
2246
+ /**
2247
+ * Extract dim ratio (overlay opacity) from cover block
2248
+ */
2249
+ function extractDimRatio(block) {
2250
+ const attrs = block.attributes || {};
2251
+ const dimRatio = attrs['dimRatio'];
2252
+ if (typeof dimRatio === 'number') {
2253
+ return dimRatio;
2254
+ }
2255
+ return 0;
2256
+ }
2257
+ /**
2258
+ * Extract min height from block
2259
+ */
2260
+ function extractMinHeight(block) {
2261
+ const attrs = block.attributes || {};
2262
+ const minHeight = attrs['minHeight'];
2263
+ const minHeightUnit = attrs['minHeightUnit'] || 'vh';
2264
+ if (typeof minHeight === 'number') {
2265
+ return { value: minHeight, unit: minHeightUnit };
2266
+ }
2267
+ return null;
2268
+ }
2269
+ /**
2270
+ * Extract heading level from heading block
2271
+ */
2272
+ function extractHeadingLevel(block) {
2273
+ const attrs = block.attributes || {};
2274
+ const level = attrs['level'];
2275
+ if (typeof level === 'number' && level >= 1 && level <= 6) {
2276
+ return level;
2277
+ }
2278
+ return 2; // Default to h2
2279
+ }
2280
+ /**
2281
+ * Extract text alignment from block
2282
+ */
2283
+ function extractTextAlign(block) {
2284
+ const attrs = block.attributes || {};
2285
+ const align = attrs['align'] || attrs['textAlign'];
2286
+ if (align === 'left' || align === 'center' || align === 'right') {
2287
+ return align;
2288
+ }
2289
+ return null;
2290
+ }
2291
+ /**
2292
+ * Extract font size from block
2293
+ */
2294
+ function extractFontSize(block) {
2295
+ const attrs = block.attributes || {};
2296
+ const fontSize = attrs['fontSize'];
2297
+ return typeof fontSize === 'string' ? fontSize : null;
2298
+ }
2299
+ /**
2300
+ * Convert image URL to Cloudflare variant if it's a Cloudflare URL
2301
+ */
2302
+ function convertImageToCloudflareVariant(url, options = {}) {
2303
+ if (!url)
2304
+ return null;
2305
+ if (isCloudflareImageUrl(url)) {
2306
+ const width = options.width || 1024;
2307
+ const height = options.height;
2308
+ return getCloudflareVariantUrl(url, { width, height });
2309
+ }
2310
+ return url;
2311
+ }
2312
+
2313
+ /**
2314
+ * Convert image URL with optional Cloudflare variant transformation
2315
+ *
2316
+ * @param url - Image URL (WordPress or Cloudflare)
2317
+ * @param options - Conversion options
2318
+ * @returns Converted URL or original if conversion not applicable
2319
+ */
2320
+ function convertImageUrl(url, options = {}) {
2321
+ if (!url)
2322
+ return null;
2323
+ const { convertToCloudflare = true, defaultWidth = 1024, defaultHeight, forceCloudflare = false, } = options;
2324
+ // If already Cloudflare URL and conversion is enabled
2325
+ if (isCloudflareImageUrl(url)) {
2326
+ if (convertToCloudflare) {
2327
+ return getCloudflareVariantUrl(url, {
2328
+ width: defaultWidth,
2329
+ height: defaultHeight,
2330
+ });
2331
+ }
2332
+ return url;
2333
+ }
2334
+ // If force conversion is enabled (not recommended - requires WordPress plugin to provide Cloudflare URLs)
2335
+ if (forceCloudflare) {
2336
+ // This would require additional logic to map WordPress URLs to Cloudflare URLs
2337
+ // which should be handled by the WordPress plugin providing Cloudflare URLs in block data
2338
+ console.warn('forceCloudflare is enabled but URL is not Cloudflare. WordPress plugin should provide Cloudflare URLs in block metadata.');
2339
+ }
2340
+ // Return original URL if not Cloudflare
2341
+ return url;
2342
+ }
2343
+ /**
2344
+ * Batch convert multiple image URLs
2345
+ */
2346
+ function convertImageUrls(urls, options = {}) {
2347
+ return urls.map(url => convertImageUrl(url, options));
2348
+ }
2349
+
2350
+ /**
2351
+ * Generic section wrapper component for consistent spacing and layout
2352
+ *
2353
+ * Usage in component mappings:
2354
+ * ```ts
2355
+ * {
2356
+ * pattern: { name: 'core/cover' },
2357
+ * component: HeroSection,
2358
+ * wrapper: SectionWrapper,
2359
+ * extractProps: (block) => ({ ... })
2360
+ * }
2361
+ * ```
2362
+ */
2363
+ const SectionWrapper = ({ children, background = 'light', spacing = 'medium', container = 'contained', className, block, }) => {
2364
+ // Background classes
2365
+ const backgroundClasses = {
2366
+ light: 'bg-white',
2367
+ dark: 'bg-gray-900 text-white',
2368
+ transparent: 'bg-transparent',
2369
+ };
2370
+ // Spacing classes (vertical padding)
2371
+ const spacingClasses = {
2372
+ none: '',
2373
+ small: 'py-8 md:py-12',
2374
+ medium: 'py-16 md:py-24',
2375
+ large: 'py-24 md:py-32',
2376
+ };
2377
+ // Container classes
2378
+ const containerClasses = {
2379
+ full: 'w-full',
2380
+ wide: 'max-w-7xl mx-auto px-4',
2381
+ contained: 'container mx-auto px-4',
2382
+ };
2383
+ // Extract additional props from block if provided
2384
+ const blockAttrs = block?.attributes || {};
2385
+ const blockBackground = blockAttrs['backgroundColor'] || blockAttrs['background'];
2386
+ const blockSpacing = blockAttrs['spacing'];
2387
+ const blockContainer = blockAttrs['container'] || blockAttrs['align'];
2388
+ // Override with block attributes if present
2389
+ const finalBackground = blockBackground || background;
2390
+ const finalSpacing = blockSpacing || spacing;
2391
+ const finalContainer = blockContainer || container;
2392
+ return (jsxRuntimeExports.jsx("section", { className: buildClassName(backgroundClasses[finalBackground] || backgroundClasses.light, spacingClasses[finalSpacing] || spacingClasses.medium, containerClasses[finalContainer] || containerClasses.contained, className), children: children }));
2393
+ };
2394
+
2395
+ exports.SectionWrapper = SectionWrapper;
1991
2396
  exports.WPContent = WPContent;
1992
2397
  exports.WPErrorBoundary = WPErrorBoundary;
1993
2398
  exports.WPPage = WPPage;
1994
2399
  exports.buildClassName = buildClassName;
2400
+ exports.convertImageToCloudflareVariant = convertImageToCloudflareVariant;
2401
+ exports.convertImageUrl = convertImageUrl;
2402
+ exports.convertImageUrls = convertImageUrls;
1995
2403
  exports.createDefaultRegistry = createDefaultRegistry;
2404
+ exports.createEnhancedRegistry = createEnhancedRegistry;
2405
+ exports.extractAlignment = extractAlignment;
2406
+ exports.extractBackgroundImage = extractBackgroundImage;
2407
+ exports.extractContent = extractContent;
2408
+ exports.extractDimRatio = extractDimRatio;
2409
+ exports.extractFontSize = extractFontSize;
2410
+ exports.extractHeadingLevel = extractHeadingLevel;
2411
+ exports.extractImageAttributes = extractImageAttributes;
2412
+ exports.extractImageUrl = extractImageUrl;
2413
+ exports.extractMediaPosition = extractMediaPosition;
2414
+ exports.extractMinHeight = extractMinHeight;
2415
+ exports.extractOverlayColor = extractOverlayColor;
2416
+ exports.extractTextAlign = extractTextAlign;
1996
2417
  exports.extractTextFromHTML = extractTextFromHTML;
2418
+ exports.extractTitle = extractTitle;
2419
+ exports.extractVerticalAlignment = extractVerticalAlignment;
2420
+ exports.findMatchingMapping = findMatchingMapping;
1997
2421
  exports.findShortcodes = findShortcodes;
1998
2422
  exports.getAlignmentClasses = getAlignmentClasses;
1999
2423
  exports.getBlockTextContent = getBlockTextContent;
@@ -2006,6 +2430,7 @@ exports.getImageUrl = getImageUrl;
2006
2430
  exports.getSectionSpacingClasses = getSectionSpacingClasses;
2007
2431
  exports.getTextAlignClasses = getTextAlignClasses;
2008
2432
  exports.isCloudflareImageUrl = isCloudflareImageUrl;
2433
+ exports.matchesPattern = matchesPattern;
2009
2434
  exports.parseGutenbergBlocks = parseGutenbergBlocks;
2010
2435
  exports.parseShortcodeAttrs = parseShortcodeAttrs;
2011
2436
  exports.renderNodes = renderNodes;