@marvalt/wparser 0.1.25 → 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 my-4', 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 my-4', 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,12 +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
- // Add spacing: mt for top (except first heading), mb for bottom
2197
- // Use larger bottom margin for headings to create visual separation
2198
- const spacingClass = level === 1 ? 'mt-8 mb-6' : level === 2 ? 'mt-6 mb-4' : 'mt-4 mb-3';
2220
+ // Get spacing from config with improved defaults
2221
+ const spacingClass = getHeadingSpacing(context.spacingConfig || context.registry.spacingConfig, level);
2199
2222
  return (jsxRuntimeExports.jsx(Tag, { className: buildClassName('font-bold text-gray-900', sizeClass, textAlign, spacingClass), children: children ?? content }));
2200
2223
  };
2201
- const Image = ({ block }) => {
2224
+ const Image = ({ block, context }) => {
2202
2225
  const imageAttrs = getImageAttributes(block);
2203
2226
  if (!imageAttrs.url)
2204
2227
  return null;
@@ -2209,13 +2232,15 @@ const Image = ({ block }) => {
2209
2232
  const height = imageAttrs.height;
2210
2233
  imageUrl = getCloudflareVariantUrl(imageUrl, { width, height });
2211
2234
  }
2212
- return (jsxRuntimeExports.jsx("img", { src: imageUrl, alt: imageAttrs.alt, width: imageAttrs.width, height: imageAttrs.height, className: "w-full h-auto rounded-lg object-cover my-4", 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" }));
2213
2237
  };
2214
- const List = ({ block, children }) => {
2238
+ const List = ({ block, children, context }) => {
2215
2239
  const attrs = block.attributes || {};
2216
2240
  const { ordered } = attrs;
2217
2241
  const Tag = ordered ? 'ol' : 'ul';
2218
- return React.createElement(Tag, { className: 'list-disc pl-6 space-y-2 text-gray-700 my-4' }, 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);
2219
2244
  };
2220
2245
  const ListItem = ({ children }) => {
2221
2246
  return jsxRuntimeExports.jsx("li", { className: "text-gray-700", children: children });
@@ -2230,7 +2255,11 @@ const Group = ({ block, children, context }) => {
2230
2255
  // Determine if this is a section-level group (has alignment) or content-level
2231
2256
  const isSection = align === 'full' || align === 'wide';
2232
2257
  const containerClass = getContainerClasses(align, layout);
2233
- 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());
2234
2263
  // Ensure container class is always applied for constrained groups
2235
2264
  const finalContainerClass = layout?.type === 'constrained' && align === 'wide'
2236
2265
  ? 'container'
@@ -2394,7 +2423,7 @@ const Fallback = ({ block, children }) => {
2394
2423
  // Minimal fallback; do not render innerHTML directly in v1 for safety
2395
2424
  return jsxRuntimeExports.jsx("div", { "data-unknown-block": block.name, children: children });
2396
2425
  };
2397
- function createDefaultRegistry(colorMapper) {
2426
+ function createDefaultRegistry(colorMapper, spacingConfig) {
2398
2427
  const renderers = {
2399
2428
  'core/paragraph': Paragraph,
2400
2429
  'core/heading': Heading,
@@ -2437,6 +2466,7 @@ function createDefaultRegistry(colorMapper) {
2437
2466
  shortcodes: {}, // Empty by default - apps extend this
2438
2467
  fallback: Fallback,
2439
2468
  colorMapper,
2469
+ spacingConfig,
2440
2470
  };
2441
2471
  }
2442
2472
  // Legacy function for backward compatibility - use getBlockTextContent instead
@@ -2526,8 +2556,8 @@ function findMatchingMapping(block, mappings) {
2526
2556
  * const registry = createEnhancedRegistry(mappings);
2527
2557
  * ```
2528
2558
  */
2529
- function createEnhancedRegistry(mappings = [], baseRegistry, colorMapper) {
2530
- const base = baseRegistry || createDefaultRegistry(colorMapper);
2559
+ function createEnhancedRegistry(mappings = [], baseRegistry, colorMapper, spacingConfig) {
2560
+ const base = baseRegistry || createDefaultRegistry(colorMapper, spacingConfig);
2531
2561
  // Create enhanced renderers that check patterns first
2532
2562
  const enhancedRenderers = {
2533
2563
  ...base.renderers,
@@ -2575,6 +2605,8 @@ function createEnhancedRegistry(mappings = [], baseRegistry, colorMapper) {
2575
2605
  matchBlock,
2576
2606
  // Use provided colorMapper or inherit from base registry
2577
2607
  colorMapper: colorMapper || base.colorMapper,
2608
+ // Use provided spacingConfig or inherit from base registry
2609
+ spacingConfig: spacingConfig || base.spacingConfig,
2578
2610
  };
2579
2611
  }
2580
2612