@marvalt/wparser 0.1.24 → 0.1.27

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 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({ block, children, context: { registry, page, colorMapper: registry.colorMapper } });
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
  }
@@ -2143,10 +2152,25 @@ function buildClassName(...classes) {
2143
2152
  .trim();
2144
2153
  }
2145
2154
 
2155
+ // Helper function to get spacing value with fallback
2156
+ // Only accepts string keys (excludes 'heading' which is an object)
2157
+ function getSpacing(spacingConfig, key, fallback) {
2158
+ return spacingConfig?.[key] || fallback;
2159
+ }
2160
+ // Helper function to get heading spacing
2161
+ function getHeadingSpacing(spacingConfig, level) {
2162
+ const headingConfig = spacingConfig?.heading;
2163
+ if (level === 1)
2164
+ return headingConfig?.h1 || 'mt-10 mb-8';
2165
+ if (level === 2)
2166
+ return headingConfig?.h2 || 'mt-8 mb-6';
2167
+ return headingConfig?.h3 || 'mt-6 mb-4';
2168
+ }
2146
2169
  const Paragraph = ({ block, context }) => {
2147
2170
  const content = getBlockTextContent(block);
2148
2171
  const attrs = block.attributes || {};
2149
2172
  const textAlign = getTextAlignClasses(attrs['align']);
2173
+ const spacing = getSpacing(context.spacingConfig || context.registry.spacingConfig, 'paragraph', 'my-6');
2150
2174
  // Check if content contains shortcodes
2151
2175
  const hasShortcodes = /\[(\w+)/.test(content);
2152
2176
  if (hasShortcodes && context.registry.shortcodes) {
@@ -2177,14 +2201,14 @@ const Paragraph = ({ block, context }) => {
2177
2201
  };
2178
2202
  const hasBlockLevelContent = React.Children.toArray(parts).some((part) => isBlockLevelElement(part));
2179
2203
  if (hasBlockLevelContent) {
2180
- // Render block-level content without <p> wrapper
2181
- return jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: parts });
2204
+ // Render block-level content without <p> wrapper, but add spacing wrapper
2205
+ return jsxRuntimeExports.jsx("div", { className: spacing, children: parts });
2182
2206
  }
2183
- return jsxRuntimeExports.jsx("p", { className: buildClassName('text-gray-700', textAlign), children: parts });
2207
+ return jsxRuntimeExports.jsx("p", { className: buildClassName('text-gray-700', spacing, textAlign), children: parts });
2184
2208
  }
2185
- return jsxRuntimeExports.jsx("p", { className: buildClassName('text-gray-700', textAlign), children: content });
2209
+ return jsxRuntimeExports.jsx("p", { className: buildClassName('text-gray-700', spacing, textAlign), children: content });
2186
2210
  };
2187
- const Heading = ({ block, children }) => {
2211
+ const Heading = ({ block, children, context }) => {
2188
2212
  const attrs = block.attributes || {};
2189
2213
  const { level = 2 } = attrs;
2190
2214
  const content = getBlockTextContent(block);
@@ -2193,9 +2217,11 @@ const Heading = ({ block, children }) => {
2193
2217
  const Tag = `h${Math.min(Math.max(Number(level) || 2, 1), 6)}`;
2194
2218
  // Default heading sizes if fontSize not specified
2195
2219
  const sizeClass = fontSize || (level === 1 ? 'text-4xl' : level === 2 ? 'text-3xl' : level === 3 ? 'text-2xl' : 'text-xl');
2196
- return (jsxRuntimeExports.jsx(Tag, { className: buildClassName('font-bold text-gray-900', sizeClass, textAlign), children: children ?? content }));
2220
+ // Get spacing from config with improved defaults
2221
+ const spacingClass = getHeadingSpacing(context.spacingConfig || context.registry.spacingConfig, level);
2222
+ return (jsxRuntimeExports.jsx(Tag, { className: buildClassName('font-bold text-gray-900', sizeClass, textAlign, spacingClass), children: children ?? content }));
2197
2223
  };
2198
- const Image = ({ block }) => {
2224
+ const Image = ({ block, context }) => {
2199
2225
  const imageAttrs = getImageAttributes(block);
2200
2226
  if (!imageAttrs.url)
2201
2227
  return null;
@@ -2206,13 +2232,15 @@ const Image = ({ block }) => {
2206
2232
  const height = imageAttrs.height;
2207
2233
  imageUrl = getCloudflareVariantUrl(imageUrl, { width, height });
2208
2234
  }
2209
- return (jsxRuntimeExports.jsx("img", { src: imageUrl, alt: imageAttrs.alt, width: imageAttrs.width, height: imageAttrs.height, className: "w-full h-auto rounded-lg object-cover", style: { maxWidth: '100%', height: 'auto' }, loading: "lazy" }));
2235
+ const spacing = getSpacing(context.spacingConfig || context.registry.spacingConfig, 'image', 'my-6');
2236
+ 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" }));
2210
2237
  };
2211
- const List = ({ block, children }) => {
2238
+ const List = ({ block, children, context }) => {
2212
2239
  const attrs = block.attributes || {};
2213
2240
  const { ordered } = attrs;
2214
2241
  const Tag = ordered ? 'ol' : 'ul';
2215
- return React.createElement(Tag, { className: 'list-disc pl-6 space-y-2 text-gray-700' }, children);
2242
+ const spacing = getSpacing(context.spacingConfig || context.registry.spacingConfig, 'list', 'my-6');
2243
+ return React.createElement(Tag, { className: buildClassName('list-disc pl-6 space-y-2 text-gray-700', spacing) }, children);
2216
2244
  };
2217
2245
  const ListItem = ({ children }) => {
2218
2246
  return jsxRuntimeExports.jsx("li", { className: "text-gray-700", children: children });
@@ -2227,7 +2255,11 @@ const Group = ({ block, children, context }) => {
2227
2255
  // Determine if this is a section-level group (has alignment) or content-level
2228
2256
  const isSection = align === 'full' || align === 'wide';
2229
2257
  const containerClass = getContainerClasses(align, layout);
2230
- const spacingClass = isSection ? getSectionSpacingClasses() : getContentSpacingClasses();
2258
+ // Get spacing from config or use defaults
2259
+ const spacingConfig = context.spacingConfig || context.registry.spacingConfig;
2260
+ const spacingClass = isSection
2261
+ ? (spacingConfig?.section || getSectionSpacingClasses())
2262
+ : (spacingConfig?.content || getContentSpacingClasses());
2231
2263
  // Ensure container class is always applied for constrained groups
2232
2264
  const finalContainerClass = layout?.type === 'constrained' && align === 'wide'
2233
2265
  ? 'container'
@@ -2391,7 +2423,7 @@ const Fallback = ({ block, children }) => {
2391
2423
  // Minimal fallback; do not render innerHTML directly in v1 for safety
2392
2424
  return jsxRuntimeExports.jsx("div", { "data-unknown-block": block.name, children: children });
2393
2425
  };
2394
- function createDefaultRegistry(colorMapper) {
2426
+ function createDefaultRegistry(colorMapper, spacingConfig) {
2395
2427
  const renderers = {
2396
2428
  'core/paragraph': Paragraph,
2397
2429
  'core/heading': Heading,
@@ -2434,6 +2466,7 @@ function createDefaultRegistry(colorMapper) {
2434
2466
  shortcodes: {}, // Empty by default - apps extend this
2435
2467
  fallback: Fallback,
2436
2468
  colorMapper,
2469
+ spacingConfig,
2437
2470
  };
2438
2471
  }
2439
2472
  // Legacy function for backward compatibility - use getBlockTextContent instead
@@ -2523,8 +2556,8 @@ function findMatchingMapping(block, mappings) {
2523
2556
  * const registry = createEnhancedRegistry(mappings);
2524
2557
  * ```
2525
2558
  */
2526
- function createEnhancedRegistry(mappings = [], baseRegistry, colorMapper) {
2527
- const base = baseRegistry || createDefaultRegistry(colorMapper);
2559
+ function createEnhancedRegistry(mappings = [], baseRegistry, colorMapper, spacingConfig) {
2560
+ const base = baseRegistry || createDefaultRegistry(colorMapper, spacingConfig);
2528
2561
  // Create enhanced renderers that check patterns first
2529
2562
  const enhancedRenderers = {
2530
2563
  ...base.renderers,
@@ -2572,6 +2605,8 @@ function createEnhancedRegistry(mappings = [], baseRegistry, colorMapper) {
2572
2605
  matchBlock,
2573
2606
  // Use provided colorMapper or inherit from base registry
2574
2607
  colorMapper: colorMapper || base.colorMapper,
2608
+ // Use provided spacingConfig or inherit from base registry
2609
+ spacingConfig: spacingConfig || base.spacingConfig,
2575
2610
  };
2576
2611
  }
2577
2612