@marvalt/wparser 0.1.25 → 0.1.29
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 +9 -0
- package/dist/index.cjs +89 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +37 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +89 -18
- package/dist/index.esm.js.map +1 -1
- package/dist/registry/defaultRegistry.d.ts +2 -2
- package/dist/registry/defaultRegistry.d.ts.map +1 -1
- package/dist/registry/enhancedRegistry.d.ts +2 -2
- package/dist/registry/enhancedRegistry.d.ts.map +1 -1
- package/dist/types.d.ts +28 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/blockExtractors.d.ts +5 -0
- package/dist/utils/blockExtractors.d.ts.map +1 -1
- package/docs/COLOR_MAPPING.md +82 -0
- package/docs/CUSTOMIZATION.md +144 -0
- package/docs/SPACING.md +136 -0
- package/docs/STYLING.md +96 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -8,6 +8,15 @@ Static-only WordPress page parser and renderer for React apps.
|
|
|
8
8
|
- Auto-hero uses featured image unless `[HEROSECTION]` is present
|
|
9
9
|
- Extensible: future adapters (Elementor/Divi) via registry
|
|
10
10
|
|
|
11
|
+
## Documentation
|
|
12
|
+
|
|
13
|
+
Comprehensive documentation is available in the `docs/` folder:
|
|
14
|
+
|
|
15
|
+
- **[STYLING.md](./docs/STYLING.md)** - How WordPress and applications control styling
|
|
16
|
+
- **[COLOR_MAPPING.md](./docs/COLOR_MAPPING.md)** - Color mapping system for background colors
|
|
17
|
+
- **[SPACING.md](./docs/SPACING.md)** - Spacing system and customization
|
|
18
|
+
- **[CUSTOMIZATION.md](./docs/CUSTOMIZATION.md)** - Complete customization guide
|
|
19
|
+
|
|
11
20
|
## Installation
|
|
12
21
|
|
|
13
22
|
Peer deps: React 18+
|
package/dist/index.cjs
CHANGED
|
@@ -1390,7 +1390,16 @@ function renderBlock(block, registry, key, options, page) {
|
|
|
1390
1390
|
const children = block.innerBlocks && block.innerBlocks.length
|
|
1391
1391
|
? block.innerBlocks.map((child, i) => renderBlock(child, registry, `${key}-${i}`, options, page))
|
|
1392
1392
|
: undefined;
|
|
1393
|
-
const node = Renderer({
|
|
1393
|
+
const node = Renderer({
|
|
1394
|
+
block,
|
|
1395
|
+
children,
|
|
1396
|
+
context: {
|
|
1397
|
+
registry,
|
|
1398
|
+
page,
|
|
1399
|
+
colorMapper: registry.colorMapper,
|
|
1400
|
+
spacingConfig: registry.spacingConfig,
|
|
1401
|
+
}
|
|
1402
|
+
});
|
|
1394
1403
|
if (options?.debugWrappers) {
|
|
1395
1404
|
return (jsxRuntimeExports.jsx("div", { "data-block": block.name, className: "wp-block", children: node }, key));
|
|
1396
1405
|
}
|
|
@@ -2050,6 +2059,36 @@ function extractBackgroundColor(block, context) {
|
|
|
2050
2059
|
// Fallback: return null (no background applied)
|
|
2051
2060
|
return null;
|
|
2052
2061
|
}
|
|
2062
|
+
/**
|
|
2063
|
+
* Extract spacer height from block attributes or innerHTML
|
|
2064
|
+
* Returns height in pixels, or null if not found
|
|
2065
|
+
*/
|
|
2066
|
+
function extractSpacerHeight(block) {
|
|
2067
|
+
const attrs = block.attributes || {};
|
|
2068
|
+
// First, try to get height from attributes
|
|
2069
|
+
const height = attrs['height'];
|
|
2070
|
+
if (typeof height === 'number') {
|
|
2071
|
+
return height;
|
|
2072
|
+
}
|
|
2073
|
+
if (typeof height === 'string') {
|
|
2074
|
+
// Parse "100px" or "100" to number
|
|
2075
|
+
const match = height.match(/^(\d+)/);
|
|
2076
|
+
if (match) {
|
|
2077
|
+
return parseInt(match[1], 10);
|
|
2078
|
+
}
|
|
2079
|
+
}
|
|
2080
|
+
// Fall back to parsing innerHTML for style="height:100px"
|
|
2081
|
+
if (block.innerHTML) {
|
|
2082
|
+
const styleMatch = block.innerHTML.match(/style=["']([^"']+)["']/i);
|
|
2083
|
+
if (styleMatch) {
|
|
2084
|
+
const heightMatch = styleMatch[1].match(/height:\s*(\d+)px/i);
|
|
2085
|
+
if (heightMatch) {
|
|
2086
|
+
return parseInt(heightMatch[1], 10);
|
|
2087
|
+
}
|
|
2088
|
+
}
|
|
2089
|
+
}
|
|
2090
|
+
return null;
|
|
2091
|
+
}
|
|
2053
2092
|
|
|
2054
2093
|
/**
|
|
2055
2094
|
* Style mapping utilities
|
|
@@ -2143,10 +2182,25 @@ function buildClassName(...classes) {
|
|
|
2143
2182
|
.trim();
|
|
2144
2183
|
}
|
|
2145
2184
|
|
|
2185
|
+
// Helper function to get spacing value with fallback
|
|
2186
|
+
// Only accepts string keys (excludes 'heading' which is an object)
|
|
2187
|
+
function getSpacing(spacingConfig, key, fallback) {
|
|
2188
|
+
return spacingConfig?.[key] || fallback;
|
|
2189
|
+
}
|
|
2190
|
+
// Helper function to get heading spacing
|
|
2191
|
+
function getHeadingSpacing(spacingConfig, level) {
|
|
2192
|
+
const headingConfig = spacingConfig?.heading;
|
|
2193
|
+
if (level === 1)
|
|
2194
|
+
return headingConfig?.h1 || 'mt-10 mb-8';
|
|
2195
|
+
if (level === 2)
|
|
2196
|
+
return headingConfig?.h2 || 'mt-8 mb-6';
|
|
2197
|
+
return headingConfig?.h3 || 'mt-6 mb-4';
|
|
2198
|
+
}
|
|
2146
2199
|
const Paragraph = ({ block, context }) => {
|
|
2147
2200
|
const content = getBlockTextContent(block);
|
|
2148
2201
|
const attrs = block.attributes || {};
|
|
2149
2202
|
const textAlign = getTextAlignClasses(attrs['align']);
|
|
2203
|
+
const spacing = getSpacing(context.spacingConfig || context.registry.spacingConfig, 'paragraph', 'my-6');
|
|
2150
2204
|
// Check if content contains shortcodes
|
|
2151
2205
|
const hasShortcodes = /\[(\w+)/.test(content);
|
|
2152
2206
|
if (hasShortcodes && context.registry.shortcodes) {
|
|
@@ -2177,14 +2231,14 @@ const Paragraph = ({ block, context }) => {
|
|
|
2177
2231
|
};
|
|
2178
2232
|
const hasBlockLevelContent = React.Children.toArray(parts).some((part) => isBlockLevelElement(part));
|
|
2179
2233
|
if (hasBlockLevelContent) {
|
|
2180
|
-
// Render block-level content without <p> wrapper
|
|
2181
|
-
return jsxRuntimeExports.jsx(
|
|
2234
|
+
// Render block-level content without <p> wrapper, but add spacing wrapper
|
|
2235
|
+
return jsxRuntimeExports.jsx("div", { className: spacing, children: parts });
|
|
2182
2236
|
}
|
|
2183
|
-
return jsxRuntimeExports.jsx("p", { className: buildClassName('text-gray-700
|
|
2237
|
+
return jsxRuntimeExports.jsx("p", { className: buildClassName('text-gray-700', spacing, textAlign), children: parts });
|
|
2184
2238
|
}
|
|
2185
|
-
return jsxRuntimeExports.jsx("p", { className: buildClassName('text-gray-700
|
|
2239
|
+
return jsxRuntimeExports.jsx("p", { className: buildClassName('text-gray-700', spacing, textAlign), children: content });
|
|
2186
2240
|
};
|
|
2187
|
-
const Heading = ({ block, children }) => {
|
|
2241
|
+
const Heading = ({ block, children, context }) => {
|
|
2188
2242
|
const attrs = block.attributes || {};
|
|
2189
2243
|
const { level = 2 } = attrs;
|
|
2190
2244
|
const content = getBlockTextContent(block);
|
|
@@ -2193,12 +2247,11 @@ const Heading = ({ block, children }) => {
|
|
|
2193
2247
|
const Tag = `h${Math.min(Math.max(Number(level) || 2, 1), 6)}`;
|
|
2194
2248
|
// Default heading sizes if fontSize not specified
|
|
2195
2249
|
const sizeClass = fontSize || (level === 1 ? 'text-4xl' : level === 2 ? 'text-3xl' : level === 3 ? 'text-2xl' : 'text-xl');
|
|
2196
|
-
//
|
|
2197
|
-
|
|
2198
|
-
const spacingClass = level === 1 ? 'mt-8 mb-6' : level === 2 ? 'mt-6 mb-4' : 'mt-4 mb-3';
|
|
2250
|
+
// Get spacing from config with improved defaults
|
|
2251
|
+
const spacingClass = getHeadingSpacing(context.spacingConfig || context.registry.spacingConfig, level);
|
|
2199
2252
|
return (jsxRuntimeExports.jsx(Tag, { className: buildClassName('font-bold text-gray-900', sizeClass, textAlign, spacingClass), children: children ?? content }));
|
|
2200
2253
|
};
|
|
2201
|
-
const Image = ({ block }) => {
|
|
2254
|
+
const Image = ({ block, context }) => {
|
|
2202
2255
|
const imageAttrs = getImageAttributes(block);
|
|
2203
2256
|
if (!imageAttrs.url)
|
|
2204
2257
|
return null;
|
|
@@ -2209,13 +2262,15 @@ const Image = ({ block }) => {
|
|
|
2209
2262
|
const height = imageAttrs.height;
|
|
2210
2263
|
imageUrl = getCloudflareVariantUrl(imageUrl, { width, height });
|
|
2211
2264
|
}
|
|
2212
|
-
|
|
2265
|
+
const spacing = getSpacing(context.spacingConfig || context.registry.spacingConfig, 'image', 'my-6');
|
|
2266
|
+
return (jsxRuntimeExports.jsx("img", { src: imageUrl, alt: imageAttrs.alt, width: imageAttrs.width, height: imageAttrs.height, className: buildClassName('w-full h-auto rounded-lg object-cover', spacing), style: { maxWidth: '100%', height: 'auto' }, loading: "lazy" }));
|
|
2213
2267
|
};
|
|
2214
|
-
const List = ({ block, children }) => {
|
|
2268
|
+
const List = ({ block, children, context }) => {
|
|
2215
2269
|
const attrs = block.attributes || {};
|
|
2216
2270
|
const { ordered } = attrs;
|
|
2217
2271
|
const Tag = ordered ? 'ol' : 'ul';
|
|
2218
|
-
|
|
2272
|
+
const spacing = getSpacing(context.spacingConfig || context.registry.spacingConfig, 'list', 'my-6');
|
|
2273
|
+
return React.createElement(Tag, { className: buildClassName('list-disc pl-6 space-y-2 text-gray-700', spacing) }, children);
|
|
2219
2274
|
};
|
|
2220
2275
|
const ListItem = ({ children }) => {
|
|
2221
2276
|
return jsxRuntimeExports.jsx("li", { className: "text-gray-700", children: children });
|
|
@@ -2230,7 +2285,11 @@ const Group = ({ block, children, context }) => {
|
|
|
2230
2285
|
// Determine if this is a section-level group (has alignment) or content-level
|
|
2231
2286
|
const isSection = align === 'full' || align === 'wide';
|
|
2232
2287
|
const containerClass = getContainerClasses(align, layout);
|
|
2233
|
-
|
|
2288
|
+
// Get spacing from config or use defaults
|
|
2289
|
+
const spacingConfig = context.spacingConfig || context.registry.spacingConfig;
|
|
2290
|
+
const spacingClass = isSection
|
|
2291
|
+
? (spacingConfig?.section || getSectionSpacingClasses())
|
|
2292
|
+
: (spacingConfig?.content || getContentSpacingClasses());
|
|
2234
2293
|
// Ensure container class is always applied for constrained groups
|
|
2235
2294
|
const finalContainerClass = layout?.type === 'constrained' && align === 'wide'
|
|
2236
2295
|
? 'container'
|
|
@@ -2394,7 +2453,7 @@ const Fallback = ({ block, children }) => {
|
|
|
2394
2453
|
// Minimal fallback; do not render innerHTML directly in v1 for safety
|
|
2395
2454
|
return jsxRuntimeExports.jsx("div", { "data-unknown-block": block.name, children: children });
|
|
2396
2455
|
};
|
|
2397
|
-
function createDefaultRegistry(colorMapper) {
|
|
2456
|
+
function createDefaultRegistry(colorMapper, spacingConfig) {
|
|
2398
2457
|
const renderers = {
|
|
2399
2458
|
'core/paragraph': Paragraph,
|
|
2400
2459
|
'core/heading': Heading,
|
|
@@ -2431,12 +2490,22 @@ function createDefaultRegistry(colorMapper) {
|
|
|
2431
2490
|
const html = block.innerHTML || '';
|
|
2432
2491
|
return jsxRuntimeExports.jsx("div", { dangerouslySetInnerHTML: { __html: html } });
|
|
2433
2492
|
},
|
|
2493
|
+
// Spacer block - adds vertical spacing
|
|
2494
|
+
'core/spacer': ({ block }) => {
|
|
2495
|
+
const height = extractSpacerHeight(block);
|
|
2496
|
+
if (height && height > 0) {
|
|
2497
|
+
return jsxRuntimeExports.jsx("div", { style: { height: `${height}px` }, "aria-hidden": "true" });
|
|
2498
|
+
}
|
|
2499
|
+
// Default fallback if height not found
|
|
2500
|
+
return jsxRuntimeExports.jsx("div", { style: { height: '100px' }, "aria-hidden": "true" });
|
|
2501
|
+
},
|
|
2434
2502
|
};
|
|
2435
2503
|
return {
|
|
2436
2504
|
renderers,
|
|
2437
2505
|
shortcodes: {}, // Empty by default - apps extend this
|
|
2438
2506
|
fallback: Fallback,
|
|
2439
2507
|
colorMapper,
|
|
2508
|
+
spacingConfig,
|
|
2440
2509
|
};
|
|
2441
2510
|
}
|
|
2442
2511
|
// Legacy function for backward compatibility - use getBlockTextContent instead
|
|
@@ -2526,8 +2595,8 @@ function findMatchingMapping(block, mappings) {
|
|
|
2526
2595
|
* const registry = createEnhancedRegistry(mappings);
|
|
2527
2596
|
* ```
|
|
2528
2597
|
*/
|
|
2529
|
-
function createEnhancedRegistry(mappings = [], baseRegistry, colorMapper) {
|
|
2530
|
-
const base = baseRegistry || createDefaultRegistry(colorMapper);
|
|
2598
|
+
function createEnhancedRegistry(mappings = [], baseRegistry, colorMapper, spacingConfig) {
|
|
2599
|
+
const base = baseRegistry || createDefaultRegistry(colorMapper, spacingConfig);
|
|
2531
2600
|
// Create enhanced renderers that check patterns first
|
|
2532
2601
|
const enhancedRenderers = {
|
|
2533
2602
|
...base.renderers,
|
|
@@ -2575,6 +2644,8 @@ function createEnhancedRegistry(mappings = [], baseRegistry, colorMapper) {
|
|
|
2575
2644
|
matchBlock,
|
|
2576
2645
|
// Use provided colorMapper or inherit from base registry
|
|
2577
2646
|
colorMapper: colorMapper || base.colorMapper,
|
|
2647
|
+
// Use provided spacingConfig or inherit from base registry
|
|
2648
|
+
spacingConfig: spacingConfig || base.spacingConfig,
|
|
2578
2649
|
};
|
|
2579
2650
|
}
|
|
2580
2651
|
|
|
@@ -2767,6 +2838,7 @@ exports.extractImageUrlWithFallback = extractImageUrlWithFallback;
|
|
|
2767
2838
|
exports.extractMediaPosition = extractMediaPosition;
|
|
2768
2839
|
exports.extractMinHeight = extractMinHeight;
|
|
2769
2840
|
exports.extractOverlayColor = extractOverlayColor;
|
|
2841
|
+
exports.extractSpacerHeight = extractSpacerHeight;
|
|
2770
2842
|
exports.extractSubtitleFromInnerBlocks = extractSubtitleFromInnerBlocks;
|
|
2771
2843
|
exports.extractTextAlign = extractTextAlign;
|
|
2772
2844
|
exports.extractTextAlignFromInnerBlocks = extractTextAlignFromInnerBlocks;
|