@marvalt/dstyler 0.1.18 → 0.1.21

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.
Files changed (52) hide show
  1. package/dist/components/AutoBlock.d.ts +8 -0
  2. package/dist/components/AutoBlock.d.ts.map +1 -1
  3. package/dist/components/AutoSection.d.ts +4 -1
  4. package/dist/components/AutoSection.d.ts.map +1 -1
  5. package/dist/components/StyledPage.d.ts +6 -0
  6. package/dist/components/StyledPage.d.ts.map +1 -1
  7. package/dist/components/index.d.ts +1 -1
  8. package/dist/components/index.d.ts.map +1 -1
  9. package/dist/engine/detectSections.d.ts.map +1 -1
  10. package/dist/engine/index.d.ts.map +1 -1
  11. package/dist/engine/renderBlock.d.ts +0 -3
  12. package/dist/engine/renderBlock.d.ts.map +1 -1
  13. package/dist/engine/selectTemplate.d.ts.map +1 -1
  14. package/dist/index.d.ts +159 -90
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.esm.js +478 -500
  17. package/dist/index.esm.js.map +1 -1
  18. package/dist/index.js +481 -499
  19. package/dist/index.js.map +1 -1
  20. package/dist/providers/ThemeProvider.d.ts.map +1 -1
  21. package/dist/providers/index.d.ts.map +1 -1
  22. package/dist/templates/FooterMinimal.d.ts.map +1 -1
  23. package/dist/templates/HeroDefault.d.ts.map +1 -1
  24. package/dist/templates/SectionBase.d.ts.map +1 -1
  25. package/dist/templates/SectionWave.d.ts.map +1 -1
  26. package/dist/templates/blocks/BlockButton.d.ts +6 -2
  27. package/dist/templates/blocks/BlockButton.d.ts.map +1 -1
  28. package/dist/templates/blocks/BlockForm.d.ts +6 -2
  29. package/dist/templates/blocks/BlockForm.d.ts.map +1 -1
  30. package/dist/templates/blocks/BlockImage.d.ts +6 -2
  31. package/dist/templates/blocks/BlockImage.d.ts.map +1 -1
  32. package/dist/templates/blocks/BlockText.d.ts +6 -2
  33. package/dist/templates/blocks/BlockText.d.ts.map +1 -1
  34. package/dist/templates/blocks/index.d.ts.map +1 -1
  35. package/dist/templates/index.d.ts +1 -0
  36. package/dist/templates/index.d.ts.map +1 -1
  37. package/dist/tokens/css-vars.d.ts.map +1 -1
  38. package/dist/tokens/index.d.ts.map +1 -1
  39. package/dist/tokens/tokens.d.ts.map +1 -1
  40. package/dist/tokens/wordpress-to-tokens.d.ts.map +1 -1
  41. package/dist/types/block.d.ts +2 -0
  42. package/dist/types/block.d.ts.map +1 -1
  43. package/dist/types/index.d.ts +1 -1
  44. package/dist/types/index.d.ts.map +1 -1
  45. package/dist/types/section.d.ts.map +1 -1
  46. package/dist/types/theme.d.ts.map +1 -1
  47. package/dist/utils/createColorMapper.d.ts.map +1 -1
  48. package/dist/utils/index.d.ts +1 -1
  49. package/dist/utils/index.d.ts.map +1 -1
  50. package/dist/utils/responsive.d.ts.map +1 -1
  51. package/package.json +52 -69
  52. package/README.md +0 -76
package/dist/index.esm.js CHANGED
@@ -1,238 +1,5 @@
1
1
  import React, { useEffect } from 'react';
2
2
 
3
- /**
4
- * @license GPL-3.0-or-later
5
- *
6
- * This file is part of the MarVAlt Open SDK.
7
- * Copyright (c) 2025 Vibune Pty Ltd.
8
- */
9
- const defaultTokens = {
10
- colors: {
11
- primary: '#1a73e8',
12
- secondary: '#34a853',
13
- background: '#ffffff',
14
- text: '#222222',
15
- heading: '#222222',
16
- default: '#ffffff',
17
- alternate: '#f5f5f5',
18
- highlight: '#e8f0fe',
19
- },
20
- spacing: {
21
- sm: 8,
22
- md: 16,
23
- lg: 32,
24
- xl: 64,
25
- },
26
- typography: {
27
- body: 'Inter, sans-serif',
28
- heading: 'Inter, sans-serif',
29
- scale: 1.2,
30
- },
31
- };
32
-
33
- /**
34
- * @license GPL-3.0-or-later
35
- *
36
- * This file is part of the MarVAlt Open SDK.
37
- * Copyright (c) 2025 Vibune Pty Ltd.
38
- */
39
- /**
40
- * Convert WordPress theme styles to design tokens
41
- */
42
- function convertWordPressToTokens(wpStyles) {
43
- if (!wpStyles) {
44
- return defaultTokens;
45
- }
46
- const palette = wpStyles.theme_palette || {};
47
- // Typography priority: Customizer (wpStyles.typography) > Theme Editor fonts (if present separately) > defaults
48
- // Note: Theme Editor fonts are not explicitly separated in current schema; assume Customizer holds them if provided.
49
- const tokens = {
50
- ...defaultTokens,
51
- colors: {
52
- ...defaultTokens.colors,
53
- ...(wpStyles.colors?.primary && { primary: wpStyles.colors.primary }),
54
- ...(wpStyles.colors?.secondary && { secondary: wpStyles.colors.secondary }),
55
- ...(wpStyles.colors?.text && { text: wpStyles.colors.text }),
56
- ...(wpStyles.colors?.heading && { heading: wpStyles.colors.heading }),
57
- ...(wpStyles.colors?.background && {
58
- background: wpStyles.colors.background,
59
- default: wpStyles.colors.background,
60
- }),
61
- },
62
- typography: {
63
- ...defaultTokens.typography,
64
- ...(wpStyles.typography?.heading_font_family && {
65
- heading: wpStyles.typography.heading_font_family
66
- }),
67
- ...(wpStyles.typography?.body_font_family && {
68
- body: wpStyles.typography.body_font_family
69
- }),
70
- },
71
- };
72
- // Ensure heading color falls back to text if not provided
73
- if (!tokens.colors.heading) {
74
- tokens.colors.heading =
75
- // Prefer explicit heading color if provided by Theme Editor
76
- wpStyles.colors?.heading ||
77
- // Then Theme Editor palette contrast (matches heading color choice in editor)
78
- palette['contrast'] ||
79
- // Then palette primary
80
- palette['primary'] ||
81
- // Then explicit primary fallback
82
- wpStyles.colors?.primary ||
83
- tokens.colors.text;
84
- }
85
- // Generate alternate and highlight colors from primary/background
86
- if (tokens.colors.primary && tokens.colors.background) {
87
- // Alternate: slightly darker/lighter than background
88
- tokens.colors.alternate = adjustBrightness(tokens.colors.background, -0.05);
89
- // Highlight: tinted with primary color
90
- tokens.colors.highlight = blendColors(tokens.colors.background, tokens.colors.primary, 0.1);
91
- }
92
- return tokens;
93
- }
94
- /**
95
- * Adjust brightness of a hex color
96
- */
97
- function adjustBrightness(hex, amount) {
98
- const num = parseInt(hex.replace('#', ''), 16);
99
- const r = Math.max(0, Math.min(255, ((num >> 16) & 0xff) + (amount * 255)));
100
- const g = Math.max(0, Math.min(255, ((num >> 8) & 0xff) + (amount * 255)));
101
- const b = Math.max(0, Math.min(255, (num & 0xff) + (amount * 255)));
102
- return `#${((r << 16) | (g << 8) | b).toString(16).padStart(6, '0')}`;
103
- }
104
- /**
105
- * Blend two colors
106
- */
107
- function blendColors(color1, color2, ratio) {
108
- const c1 = hexToRgb(color1);
109
- const c2 = hexToRgb(color2);
110
- if (!c1 || !c2)
111
- return color1;
112
- const r = Math.round(c1.r + (c2.r - c1.r) * ratio);
113
- const g = Math.round(c1.g + (c2.g - c1.g) * ratio);
114
- const b = Math.round(c1.b + (c2.b - c1.b) * ratio);
115
- return `rgb(${r}, ${g}, ${b})`;
116
- }
117
- function hexToRgb(hex) {
118
- const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
119
- return result
120
- ? {
121
- r: parseInt(result[1], 16),
122
- g: parseInt(result[2], 16),
123
- b: parseInt(result[3], 16),
124
- }
125
- : null;
126
- }
127
-
128
- /**
129
- * @license GPL-3.0-or-later
130
- *
131
- * This file is part of the MarVAlt Open SDK.
132
- * Copyright (c) 2025 Vibune Pty Ltd.
133
- */
134
- const THEME_STYLE_ID = 'dstyler-theme-vars';
135
- function tokensToCSS(tokens) {
136
- return `
137
- --dstyler-color-primary: ${tokens.colors.primary};
138
- --dstyler-color-secondary: ${tokens.colors.secondary};
139
- --dstyler-color-background: ${tokens.colors.background};
140
- --dstyler-color-text: ${tokens.colors.text};
141
- --dstyler-color-heading: ${tokens.colors.heading || tokens.colors.text};
142
- --dstyler-color-default: ${tokens.colors.default};
143
- --dstyler-color-alternate: ${tokens.colors.alternate};
144
- --dstyler-color-highlight: ${tokens.colors.highlight};
145
- --dstyler-spacing-sm: ${tokens.spacing.sm}px;
146
- --dstyler-spacing-md: ${tokens.spacing.md}px;
147
- --dstyler-spacing-lg: ${tokens.spacing.lg}px;
148
- --dstyler-spacing-xl: ${tokens.spacing.xl}px;
149
- --dstyler-font-body: ${tokens.typography.body};
150
- --dstyler-font-heading: ${tokens.typography.heading};
151
- --dstyler-font-scale: ${tokens.typography.scale};
152
- `;
153
- }
154
- function ensureStyleElement() {
155
- if (typeof document === 'undefined')
156
- return null;
157
- let el = document.getElementById(THEME_STYLE_ID);
158
- if (!el) {
159
- el = document.createElement('style');
160
- el.id = THEME_STYLE_ID;
161
- document.head.appendChild(el);
162
- }
163
- return el;
164
- }
165
- /**
166
- * Inject CSS variables from design tokens into :root
167
- */
168
- function injectCSSVariables(tokens) {
169
- const el = ensureStyleElement();
170
- if (!el)
171
- return;
172
- el.textContent = `:root { ${tokensToCSS(tokens)} }`;
173
- }
174
- /**
175
- * Inject CSS variables for both light and dark themes.
176
- * Light applies to :root, dark applies when [data-theme="dark"] is present.
177
- */
178
- function injectDualThemeCSS(light, dark) {
179
- const el = ensureStyleElement();
180
- if (!el)
181
- return;
182
- el.textContent = `
183
- :root { ${tokensToCSS(light)} }
184
- :root[data-theme="dark"] { ${tokensToCSS(dark)} }
185
- `;
186
- }
187
-
188
- /**
189
- * @license GPL-3.0-or-later
190
- *
191
- * This file is part of the MarVAlt Open SDK.
192
- * Copyright (c) 2025 Vibune Pty Ltd.
193
- */
194
- /**
195
- * ThemeProvider - Provides design tokens to the application
196
- *
197
- * Priority order:
198
- * 1. customTokens (highest priority - overrides everything)
199
- * 2. WordPress styles (converted to tokens)
200
- * 3. Default tokens (fallback)
201
- */
202
- const ThemeProvider = ({ children, wpStyles, customTokens, darkWpStyles, darkTokens, mode = 'light', }) => {
203
- useEffect(() => {
204
- // Light tokens: custom -> wpStyles -> default
205
- const lightTokens = customTokens || convertWordPressToTokens(wpStyles);
206
- // Dark tokens: provided -> wpStylesDark -> fallback to light
207
- const resolvedDarkTokens = darkTokens || (darkWpStyles ? convertWordPressToTokens(darkWpStyles) : lightTokens);
208
- if (mode === 'dark') {
209
- injectDualThemeCSS(lightTokens, resolvedDarkTokens);
210
- if (typeof document !== 'undefined') {
211
- document.documentElement.setAttribute('data-theme', 'dark');
212
- }
213
- return;
214
- }
215
- if (mode === 'system') {
216
- const prefersDark = typeof window !== 'undefined' && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
217
- injectDualThemeCSS(lightTokens, resolvedDarkTokens);
218
- if (typeof document !== 'undefined') {
219
- document.documentElement.setAttribute('data-theme', prefersDark ? 'dark' : 'light');
220
- }
221
- return;
222
- }
223
- // Default to light
224
- injectDualThemeCSS(lightTokens, resolvedDarkTokens);
225
- if (typeof document !== 'undefined') {
226
- document.documentElement.setAttribute('data-theme', 'light');
227
- }
228
- }, [wpStyles, customTokens, darkWpStyles, darkTokens, mode]);
229
- // Return children if provided, otherwise return null (theme still applies via useEffect)
230
- if (children === undefined || children === null) {
231
- return null;
232
- }
233
- return React.createElement(React.Fragment, null, children);
234
- };
235
-
236
3
  var jsxRuntime = {exports: {}};
237
4
 
238
5
  var reactJsxRuntime_production = {};
@@ -648,21 +415,80 @@ if (process.env.NODE_ENV === 'production') {
648
415
  var jsxRuntimeExports = jsxRuntime.exports;
649
416
 
650
417
  /**
651
- * @license GPL-3.0-or-later
652
- *
653
- * This file is part of the MarVAlt Open SDK.
654
- * Copyright (c) 2025 Vibune Pty Ltd.
418
+ * Detect sections from WordPress blocks
419
+ * Sections are defined by core/group blocks (with or without alignment)
420
+ * Sub-sections are core/columns blocks inside groups
655
421
  */
422
+ function detectSections(blocks) {
423
+ const sections = [];
424
+ let sectionIndex = 0;
425
+ for (const block of blocks) {
426
+ // core/group blocks are sections
427
+ if (block.name === 'core/group') {
428
+ const attrs = block.attributes || {};
429
+ const className = attrs.className;
430
+ const customId = attrs.id;
431
+ // Extract blocks from innerBlocks
432
+ const innerBlocks = block.innerBlocks || [];
433
+ sections.push({
434
+ id: `section-${sectionIndex}`,
435
+ type: 'section',
436
+ block,
437
+ blocks: innerBlocks,
438
+ index: sectionIndex,
439
+ customClass: className,
440
+ customId,
441
+ });
442
+ sectionIndex++;
443
+ }
444
+ }
445
+ return sections;
446
+ }
656
447
  /**
657
- * Select template component based on section properties
448
+ * Determine section style based on alternating logic and custom classes
449
+ * Rules:
450
+ * - default is always first
451
+ * - after default follows alternate
452
+ * - highlight resets - next section is default
658
453
  */
659
- function selectTemplate(section) {
660
- const block = section.block;
661
- const attrs = block.attributes || {};
454
+ function determineSectionStyle(section, previousStyle) {
662
455
  const className = section.customClass?.toLowerCase() || '';
663
- // Check for hero/cover blocks
664
- if (block.name === 'core/cover') {
665
- return 'HeroDefault';
456
+ // Check for custom class overrides first
457
+ if (className.includes('highlight') || className.includes('highlight-section')) {
458
+ return 'highlight';
459
+ }
460
+ if (className.includes('dark') || className.includes('dark-section')) {
461
+ return 'alternate';
462
+ }
463
+ if (className.includes('default') || className.includes('default-section')) {
464
+ return 'default';
465
+ }
466
+ // Alternating logic
467
+ if (section.index === 0) {
468
+ return 'default';
469
+ }
470
+ if (previousStyle === 'highlight') {
471
+ return 'default';
472
+ }
473
+ if (previousStyle === 'default') {
474
+ return 'alternate';
475
+ }
476
+ if (previousStyle === 'alternate') {
477
+ return 'default';
478
+ }
479
+ return 'default';
480
+ }
481
+
482
+ /**
483
+ * Select template component based on section properties
484
+ */
485
+ function selectTemplate(section) {
486
+ const block = section.block;
487
+ const attrs = block.attributes || {};
488
+ const className = section.customClass?.toLowerCase() || '';
489
+ // Check for hero/cover blocks
490
+ if (block.name === 'core/cover') {
491
+ return 'HeroDefault';
666
492
  }
667
493
  // Check for footer (could be detected by block name or class)
668
494
  if (className.includes('footer') || block.name === 'core/footer') {
@@ -676,101 +502,6 @@ function selectTemplate(section) {
676
502
  return 'SectionBase';
677
503
  }
678
504
 
679
- const SectionBase = ({ section, children }) => {
680
- const style = section.style || 'default';
681
- const bgColor = `var(--dstyler-color-${style})`;
682
- const className = [
683
- 'dstyler-section',
684
- `dstyler-section-${style}`,
685
- section.customClass,
686
- ].filter(Boolean).join(' ');
687
- return (jsxRuntimeExports.jsx("section", { className: className, id: section.customId, style: {
688
- backgroundColor: bgColor,
689
- padding: 'var(--dstyler-spacing-xl) var(--dstyler-spacing-md)',
690
- }, children: jsxRuntimeExports.jsx("div", { style: {
691
- maxWidth: 'var(--dstyler-container-max-width, 1200px)',
692
- margin: '0 auto',
693
- }, children: children }) }));
694
- };
695
-
696
- const SectionWave = ({ section, children, waveTop = true, waveBottom = true, }) => {
697
- const style = section.style || 'default';
698
- const bgColor = `var(--dstyler-color-${style})`;
699
- const className = [
700
- 'dstyler-section',
701
- 'dstyler-section-wave',
702
- `dstyler-section-${style}`,
703
- section.customClass,
704
- ].filter(Boolean).join(' ');
705
- // Wave SVG
706
- const waveSvg = (jsxRuntimeExports.jsx("svg", { viewBox: "0 0 1440 120", preserveAspectRatio: "none", style: {
707
- width: '100%',
708
- height: '60px',
709
- display: 'block',
710
- fill: bgColor,
711
- }, children: jsxRuntimeExports.jsx("path", { d: "M0,60 C240,0 480,120 720,60 C960,0 1200,120 1440,60 L1440,120 L0,120 Z" }) }));
712
- return (jsxRuntimeExports.jsxs("section", { className: className, id: section.customId, style: {
713
- backgroundColor: bgColor,
714
- position: 'relative',
715
- }, children: [waveTop && (jsxRuntimeExports.jsx("div", { style: { marginTop: '-1px' }, children: waveSvg })), jsxRuntimeExports.jsx("div", { style: {
716
- padding: 'var(--dstyler-spacing-xl) var(--dstyler-spacing-md)',
717
- }, children: jsxRuntimeExports.jsx("div", { style: {
718
- maxWidth: 'var(--dstyler-container-max-width, 1200px)',
719
- margin: '0 auto',
720
- }, children: children }) }), waveBottom && (jsxRuntimeExports.jsx("div", { style: { marginBottom: '-1px', transform: 'rotate(180deg)' }, children: waveSvg }))] }));
721
- };
722
-
723
- const HeroDefault = ({ section, children }) => {
724
- const style = section.style || 'default';
725
- const bgColor = `var(--dstyler-color-${style})`;
726
- const className = [
727
- 'dstyler-hero',
728
- 'dstyler-hero-default',
729
- `dstyler-hero-${style}`,
730
- section.customClass,
731
- ].filter(Boolean).join(' ');
732
- return (jsxRuntimeExports.jsx("section", { className: className, id: section.customId, style: {
733
- backgroundColor: bgColor,
734
- padding: 'var(--dstyler-spacing-xl) var(--dstyler-spacing-md)',
735
- minHeight: '50vh',
736
- display: 'flex',
737
- alignItems: 'center',
738
- justifyContent: 'center',
739
- }, children: jsxRuntimeExports.jsx("div", { style: {
740
- maxWidth: 'var(--dstyler-container-max-width, 1200px)',
741
- margin: '0 auto',
742
- textAlign: 'center',
743
- }, children: children }) }));
744
- };
745
-
746
- const FooterMinimal = ({ section, children }) => {
747
- const style = section.style || 'default';
748
- const bgColor = `var(--dstyler-color-${style})`;
749
- const className = [
750
- 'dstyler-footer',
751
- 'dstyler-footer-minimal',
752
- `dstyler-footer-${style}`,
753
- section.customClass,
754
- ].filter(Boolean).join(' ');
755
- return (jsxRuntimeExports.jsx("footer", { className: className, id: section.customId, style: {
756
- backgroundColor: bgColor,
757
- padding: 'var(--dstyler-spacing-lg) var(--dstyler-spacing-md)',
758
- borderTop: '1px solid var(--dstyler-color-alternate)',
759
- }, children: jsxRuntimeExports.jsx("div", { style: {
760
- maxWidth: 'var(--dstyler-container-max-width, 1200px)',
761
- margin: '0 auto',
762
- textAlign: 'center',
763
- fontSize: '0.875rem',
764
- color: 'var(--dstyler-color-text)',
765
- }, children: children }) }));
766
- };
767
-
768
- /**
769
- * @license GPL-3.0-or-later
770
- *
771
- * This file is part of the MarVAlt Open SDK.
772
- * Copyright (c) 2025 Vibune Pty Ltd.
773
- */
774
505
  /**
775
506
  * Select block renderer based on block type
776
507
  */
@@ -791,7 +522,7 @@ function selectBlockRenderer(block) {
791
522
  case 'core/shortcode':
792
523
  // Check if it's a form shortcode
793
524
  const attrs = block.attributes || {};
794
- const content = attrs.content || attrs.html || '';
525
+ const content = (attrs.content || attrs.html || '');
795
526
  if (content.includes('[gravityform') || content.includes('[mauticform')) {
796
527
  return 'BlockForm';
797
528
  }
@@ -803,7 +534,7 @@ function selectBlockRenderer(block) {
803
534
 
804
535
  const BlockText = ({ block, className }) => {
805
536
  const attrs = block.attributes || {};
806
- const content = attrs.content || attrs.text || '';
537
+ const content = (attrs.content || attrs.text || '');
807
538
  const tagName = block.name === 'core/heading'
808
539
  ? `h${attrs.level || 2}`
809
540
  : 'p';
@@ -823,40 +554,38 @@ const BlockText = ({ block, className }) => {
823
554
 
824
555
  const BlockImage = ({ block, className }) => {
825
556
  const attrs = block.attributes || {};
826
- const url = attrs.url || attrs.sourceUrl || '';
827
- const alt = attrs.alt || attrs.altText || '';
557
+ const url = (attrs.url || attrs.sourceUrl || '');
558
+ const alt = (attrs.alt || attrs.altText || '');
828
559
  const width = attrs.width;
829
560
  const height = attrs.height;
830
561
  if (!url)
831
562
  return null;
832
- const style = {
833
- maxWidth: '100%',
834
- height: 'auto',
835
- marginBottom: 'var(--dstyler-spacing-md)',
836
- borderRadius: '8px',
837
- };
838
- return (jsxRuntimeExports.jsx("img", { src: url, alt: alt, width: width, height: height, className: className, style: style, loading: "lazy" }));
563
+ return (jsxRuntimeExports.jsx("img", { src: url, alt: alt, width: width, height: height, className: className, style: {
564
+ maxWidth: '100%',
565
+ height: 'auto',
566
+ marginBottom: 'var(--dstyler-spacing-md)',
567
+ borderRadius: '8px',
568
+ }, loading: "lazy" }));
839
569
  };
840
570
 
841
571
  const BlockButton = ({ block, className }) => {
842
572
  const attrs = block.attributes || {};
843
- const text = attrs.text || attrs.label || 'Button';
844
- const url = attrs.url || attrs.linkUrl || '#';
573
+ const text = (attrs.text || attrs.label || 'Button');
574
+ const url = (attrs.url || attrs.linkUrl || '#');
845
575
  const isExternal = typeof window !== 'undefined'
846
576
  ? url.startsWith('http') && !url.includes(window.location.hostname)
847
577
  : url.startsWith('http');
848
- const style = {
849
- display: 'inline-block',
850
- padding: 'var(--dstyler-spacing-md) var(--dstyler-spacing-lg)',
851
- backgroundColor: 'var(--dstyler-color-primary)',
852
- color: '#ffffff',
853
- textDecoration: 'none',
854
- borderRadius: '4px',
855
- fontWeight: '500',
856
- marginBottom: 'var(--dstyler-spacing-md)',
857
- transition: 'opacity 0.2s',
858
- };
859
- return (jsxRuntimeExports.jsx("a", { href: url, target: isExternal ? '_blank' : undefined, rel: isExternal ? 'noopener noreferrer' : undefined, className: className, style: style, onMouseEnter: (e) => {
578
+ return (jsxRuntimeExports.jsx("a", { href: url, target: isExternal ? '_blank' : undefined, rel: isExternal ? 'noopener noreferrer' : undefined, className: className, style: {
579
+ display: 'inline-block',
580
+ padding: 'var(--dstyler-spacing-md) var(--dstyler-spacing-lg)',
581
+ backgroundColor: 'var(--dstyler-color-primary)',
582
+ color: '#ffffff',
583
+ textDecoration: 'none',
584
+ borderRadius: '4px',
585
+ fontWeight: '500',
586
+ marginBottom: 'var(--dstyler-spacing-md)',
587
+ transition: 'opacity 0.2s',
588
+ }, onMouseEnter: (e) => {
860
589
  e.currentTarget.style.opacity = '0.9';
861
590
  }, onMouseLeave: (e) => {
862
591
  e.currentTarget.style.opacity = '1';
@@ -865,16 +594,22 @@ const BlockButton = ({ block, className }) => {
865
594
 
866
595
  const BlockForm = ({ block, className }) => {
867
596
  const attrs = block.attributes || {};
868
- const content = attrs.content || attrs.html || '';
597
+ const content = (attrs.content || attrs.html || '');
869
598
  // For now, just render the HTML content
870
599
  // In the future, this could parse and render using Gravity Forms or Mautic components
871
- const style = {
872
- marginBottom: 'var(--dstyler-spacing-lg)',
873
- };
874
- return (jsxRuntimeExports.jsx("div", { className: className, style: style, dangerouslySetInnerHTML: { __html: content } }));
600
+ return (jsxRuntimeExports.jsx("div", { className: className, style: {
601
+ marginBottom: 'var(--dstyler-spacing-lg)',
602
+ }, dangerouslySetInnerHTML: { __html: content } }));
875
603
  };
876
604
 
877
- const AutoBlock = ({ block, registry }) => {
605
+ /**
606
+ * AutoBlock - Automatically selects and renders the appropriate block renderer
607
+ *
608
+ * Priority:
609
+ * 1. Use registry renderer if available (integrates with wparser)
610
+ * 2. Use dstyler's built-in block renderers
611
+ */
612
+ const AutoBlock = ({ block, registry, className }) => {
878
613
  // If registry is provided, use it for rendering (integrates with wparser)
879
614
  if (registry && registry.renderers[block.name]) {
880
615
  const Renderer = registry.renderers[block.name];
@@ -884,19 +619,111 @@ const AutoBlock = ({ block, registry }) => {
884
619
  const rendererName = selectBlockRenderer(block);
885
620
  switch (rendererName) {
886
621
  case 'BlockText':
887
- return jsxRuntimeExports.jsx(BlockText, { block: block });
622
+ return jsxRuntimeExports.jsx(BlockText, { block: block, className: className });
888
623
  case 'BlockImage':
889
- return jsxRuntimeExports.jsx(BlockImage, { block: block });
624
+ return jsxRuntimeExports.jsx(BlockImage, { block: block, className: className });
890
625
  case 'BlockButton':
891
- return jsxRuntimeExports.jsx(BlockButton, { block: block });
626
+ return jsxRuntimeExports.jsx(BlockButton, { block: block, className: className });
892
627
  case 'BlockForm':
893
- return jsxRuntimeExports.jsx(BlockForm, { block: block });
628
+ return jsxRuntimeExports.jsx(BlockForm, { block: block, className: className });
894
629
  default:
895
630
  // Fallback: render block name or content
896
631
  return (jsxRuntimeExports.jsx("div", { style: { marginBottom: 'var(--dstyler-spacing-md)' }, children: jsxRuntimeExports.jsxs("pre", { style: { fontSize: '0.875rem', color: '#666' }, children: [block.name, ": ", JSON.stringify(block.attributes, null, 2)] }) }));
897
632
  }
898
633
  };
899
634
 
635
+ const SectionBase = ({ section, children }) => {
636
+ const style = section.style || 'default';
637
+ const bgColor = `var(--dstyler-color-${style})`;
638
+ const className = [
639
+ 'dstyler-section',
640
+ `dstyler-section-${style}`,
641
+ section.customClass,
642
+ ].filter(Boolean).join(' ');
643
+ return (jsxRuntimeExports.jsx("section", { className: className, id: section.customId, style: {
644
+ backgroundColor: bgColor,
645
+ padding: 'var(--dstyler-spacing-xl) var(--dstyler-spacing-md)',
646
+ }, children: jsxRuntimeExports.jsx("div", { style: {
647
+ maxWidth: 'var(--dstyler-container-max-width, 1200px)',
648
+ margin: '0 auto',
649
+ }, children: children }) }));
650
+ };
651
+
652
+ const SectionWave = ({ section, children, waveTop = true, waveBottom = true, }) => {
653
+ const style = section.style || 'default';
654
+ const bgColor = `var(--dstyler-color-${style})`;
655
+ const className = [
656
+ 'dstyler-section',
657
+ 'dstyler-section-wave',
658
+ `dstyler-section-${style}`,
659
+ section.customClass,
660
+ ].filter(Boolean).join(' ');
661
+ // Wave SVG
662
+ const waveSvg = (jsxRuntimeExports.jsx("svg", { viewBox: "0 0 1440 120", preserveAspectRatio: "none", style: {
663
+ width: '100%',
664
+ height: '60px',
665
+ display: 'block',
666
+ fill: bgColor,
667
+ }, children: jsxRuntimeExports.jsx("path", { d: "M0,60 C240,0 480,120 720,60 C960,0 1200,120 1440,60 L1440,120 L0,120 Z" }) }));
668
+ return (jsxRuntimeExports.jsxs("section", { className: className, id: section.customId, style: {
669
+ backgroundColor: bgColor,
670
+ position: 'relative',
671
+ }, children: [waveTop && jsxRuntimeExports.jsx("div", { style: { marginTop: '-1px' }, children: waveSvg }), jsxRuntimeExports.jsx("div", { style: {
672
+ padding: 'var(--dstyler-spacing-xl) var(--dstyler-spacing-md)',
673
+ }, children: jsxRuntimeExports.jsx("div", { style: {
674
+ maxWidth: 'var(--dstyler-container-max-width, 1200px)',
675
+ margin: '0 auto',
676
+ }, children: children }) }), waveBottom && (jsxRuntimeExports.jsx("div", { style: { marginBottom: '-1px', transform: 'rotate(180deg)' }, children: waveSvg }))] }));
677
+ };
678
+
679
+ const HeroDefault = ({ section, children }) => {
680
+ const style = section.style || 'default';
681
+ const bgColor = `var(--dstyler-color-${style})`;
682
+ const className = [
683
+ 'dstyler-hero',
684
+ 'dstyler-hero-default',
685
+ `dstyler-hero-${style}`,
686
+ section.customClass,
687
+ ].filter(Boolean).join(' ');
688
+ return (jsxRuntimeExports.jsx("section", { className: className, id: section.customId, style: {
689
+ backgroundColor: bgColor,
690
+ padding: 'var(--dstyler-spacing-xl) var(--dstyler-spacing-md)',
691
+ minHeight: '50vh',
692
+ display: 'flex',
693
+ alignItems: 'center',
694
+ justifyContent: 'center',
695
+ }, children: jsxRuntimeExports.jsx("div", { style: {
696
+ maxWidth: 'var(--dstyler-container-max-width, 1200px)',
697
+ margin: '0 auto',
698
+ textAlign: 'center',
699
+ }, children: children }) }));
700
+ };
701
+
702
+ const FooterMinimal = ({ section, children }) => {
703
+ const style = section.style || 'default';
704
+ const bgColor = `var(--dstyler-color-${style})`;
705
+ const className = [
706
+ 'dstyler-footer',
707
+ 'dstyler-footer-minimal',
708
+ `dstyler-footer-${style}`,
709
+ section.customClass,
710
+ ].filter(Boolean).join(' ');
711
+ return (jsxRuntimeExports.jsx("footer", { className: className, id: section.customId, style: {
712
+ backgroundColor: bgColor,
713
+ padding: 'var(--dstyler-spacing-lg) var(--dstyler-spacing-md)',
714
+ borderTop: '1px solid var(--dstyler-color-alternate)',
715
+ }, children: jsxRuntimeExports.jsx("div", { style: {
716
+ maxWidth: 'var(--dstyler-container-max-width, 1200px)',
717
+ margin: '0 auto',
718
+ textAlign: 'center',
719
+ fontSize: '0.875rem',
720
+ color: 'var(--dstyler-color-text)',
721
+ }, children: children }) }));
722
+ };
723
+
724
+ /**
725
+ * AutoSection - Automatically selects and renders the appropriate section template
726
+ */
900
727
  const AutoSection = ({ section, registry }) => {
901
728
  const templateName = selectTemplate(section);
902
729
  // Render blocks using AutoBlock or registry
@@ -917,85 +744,20 @@ const AutoSection = ({ section, registry }) => {
917
744
  return (jsxRuntimeExports.jsx(SectionWave, { section: section, waveTop: waveTop, waveBottom: waveBottom, children: renderBlocks() }));
918
745
  }
919
746
  case 'HeroDefault':
920
- return (jsxRuntimeExports.jsx(HeroDefault, { section: section, children: renderBlocks() }));
747
+ return jsxRuntimeExports.jsx(HeroDefault, { section: section, children: renderBlocks() });
921
748
  case 'FooterMinimal':
922
- return (jsxRuntimeExports.jsx(FooterMinimal, { section: section, children: renderBlocks() }));
749
+ return jsxRuntimeExports.jsx(FooterMinimal, { section: section, children: renderBlocks() });
923
750
  default:
924
- return (jsxRuntimeExports.jsx(SectionBase, { section: section, children: renderBlocks() }));
751
+ return jsxRuntimeExports.jsx(SectionBase, { section: section, children: renderBlocks() });
925
752
  }
926
753
  };
927
754
 
928
755
  /**
929
- * @license GPL-3.0-or-later
756
+ * StyledPage - Main entry point for dstyler
930
757
  *
931
- * This file is part of the MarVAlt Open SDK.
932
- * Copyright (c) 2025 Vibune Pty Ltd.
933
- */
934
- /**
935
- * Detect sections from WordPress blocks
936
- * Sections are defined by core/group blocks (with or without alignment)
937
- * Sub-sections are core/columns blocks inside groups
758
+ * Detects sections from WordPress blocks and applies alternating styles
759
+ * Integrates with wparser's registry for block rendering
938
760
  */
939
- function detectSections(blocks) {
940
- const sections = [];
941
- let sectionIndex = 0;
942
- for (const block of blocks) {
943
- // core/group blocks are sections
944
- if (block.name === 'core/group') {
945
- const attrs = block.attributes || {};
946
- const className = attrs.className;
947
- const customId = attrs.id;
948
- // Extract blocks from innerBlocks
949
- const innerBlocks = block.innerBlocks || [];
950
- sections.push({
951
- id: `section-${sectionIndex}`,
952
- type: 'section',
953
- block,
954
- blocks: innerBlocks,
955
- index: sectionIndex,
956
- customClass: className,
957
- customId,
958
- });
959
- sectionIndex++;
960
- }
961
- }
962
- return sections;
963
- }
964
- /**
965
- * Determine section style based on alternating logic and custom classes
966
- * Rules:
967
- * - default is always first
968
- * - after default follows alternate
969
- * - highlight resets - next section is default
970
- */
971
- function determineSectionStyle(section, previousStyle) {
972
- const className = section.customClass?.toLowerCase() || '';
973
- // Check for custom class overrides first
974
- if (className.includes('highlight') || className.includes('highlight-section')) {
975
- return 'highlight';
976
- }
977
- if (className.includes('dark') || className.includes('dark-section')) {
978
- return 'alternate';
979
- }
980
- if (className.includes('default') || className.includes('default-section')) {
981
- return 'default';
982
- }
983
- // Alternating logic
984
- if (section.index === 0) {
985
- return 'default';
986
- }
987
- if (previousStyle === 'highlight') {
988
- return 'default';
989
- }
990
- if (previousStyle === 'default') {
991
- return 'alternate';
992
- }
993
- if (previousStyle === 'alternate') {
994
- return 'default';
995
- }
996
- return 'default';
997
- }
998
-
999
761
  const StyledPage = ({ page, registry }) => {
1000
762
  const blocks = page.blocks || [];
1001
763
  // Detect sections from blocks
@@ -1010,25 +772,175 @@ const StyledPage = ({ page, registry }) => {
1010
772
  style,
1011
773
  };
1012
774
  });
1013
- return (jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: styledSections.map((section) => (jsxRuntimeExports.jsx(AutoSection, { section: section, registry: registry }, section.id))) }));
775
+ return (jsxRuntimeExports.jsx(React.Fragment, { children: styledSections.map((section) => (jsxRuntimeExports.jsx(AutoSection, { section: section, registry: registry }, section.id))) }));
776
+ };
777
+
778
+ const defaultTokens = {
779
+ colors: {
780
+ primary: '#1a73e8',
781
+ secondary: '#34a853',
782
+ background: '#ffffff',
783
+ text: '#222222',
784
+ heading: '#222222',
785
+ default: '#ffffff',
786
+ alternate: '#f5f5f5',
787
+ highlight: '#e8f0fe',
788
+ },
789
+ spacing: {
790
+ sm: 8,
791
+ md: 16,
792
+ lg: 32,
793
+ xl: 64,
794
+ },
795
+ typography: {
796
+ body: 'Inter, sans-serif',
797
+ heading: 'Inter, sans-serif',
798
+ scale: 1.2,
799
+ },
1014
800
  };
1015
801
 
1016
802
  /**
1017
- * @license GPL-3.0-or-later
1018
- *
1019
- * This file is part of the MarVAlt Open SDK.
1020
- * Copyright (c) 2025 Vibune Pty Ltd.
803
+ * Adjust brightness of a hex color
1021
804
  */
805
+ function adjustBrightness(hex, amount) {
806
+ const num = parseInt(hex.replace('#', ''), 16);
807
+ const r = Math.max(0, Math.min(255, ((num >> 16) & 0xff) + (amount * 255)));
808
+ const g = Math.max(0, Math.min(255, ((num >> 8) & 0xff) + (amount * 255)));
809
+ const b = Math.max(0, Math.min(255, (num & 0xff) + (amount * 255)));
810
+ return `#${((r << 16) | (g << 8) | b).toString(16).padStart(6, '0')}`;
811
+ }
1022
812
  /**
1023
- * Responsive utility functions
813
+ * Blend two colors
1024
814
  */
1025
- function getResponsiveValue(mobile, tablet, desktop) {
1026
- if (!tablet && !desktop) {
1027
- return typeof mobile === 'number' ? `${mobile}px` : mobile;
815
+ function blendColors(color1, color2, ratio) {
816
+ const c1 = hexToRgb(color1);
817
+ const c2 = hexToRgb(color2);
818
+ if (!c1 || !c2)
819
+ return color1;
820
+ const r = Math.round(c1.r + (c2.r - c1.r) * ratio);
821
+ const g = Math.round(c1.g + (c2.g - c1.g) * ratio);
822
+ const b = Math.round(c1.b + (c2.b - c1.b) * ratio);
823
+ return `rgb(${r}, ${g}, ${b})`;
824
+ }
825
+ function hexToRgb(hex) {
826
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
827
+ return result
828
+ ? {
829
+ r: parseInt(result[1], 16),
830
+ g: parseInt(result[2], 16),
831
+ b: parseInt(result[3], 16),
832
+ }
833
+ : null;
834
+ }
835
+ /**
836
+ * Convert WordPress theme styles to design tokens
837
+ */
838
+ function convertWordPressToTokens(wpStyles) {
839
+ if (!wpStyles) {
840
+ return defaultTokens;
1028
841
  }
1029
- // For now, return mobile value
1030
- // In the future, this could use CSS custom properties with media queries
1031
- return typeof mobile === 'number' ? `${mobile}px` : mobile;
842
+ const palette = wpStyles.theme_palette || {};
843
+ // Typography priority: Customizer (wpStyles.typography) > Theme Editor fonts > defaults
844
+ const tokens = {
845
+ ...defaultTokens,
846
+ colors: {
847
+ ...defaultTokens.colors,
848
+ ...(wpStyles.colors?.primary && { primary: wpStyles.colors.primary }),
849
+ ...(wpStyles.colors?.secondary && { secondary: wpStyles.colors.secondary }),
850
+ ...(wpStyles.colors?.text && { text: wpStyles.colors.text }),
851
+ // heading handled below to allow palette fallback
852
+ ...(wpStyles.colors?.background && {
853
+ background: wpStyles.colors.background,
854
+ default: wpStyles.colors.background,
855
+ }),
856
+ },
857
+ typography: {
858
+ ...defaultTokens.typography,
859
+ ...(wpStyles.typography?.heading_font_family && {
860
+ heading: wpStyles.typography.heading_font_family,
861
+ }),
862
+ ...(wpStyles.typography?.body_font_family && {
863
+ body: wpStyles.typography.body_font_family,
864
+ }),
865
+ },
866
+ };
867
+ // Explicit heading override (may be undefined/empty), then fallback below
868
+ tokens.colors.heading = wpStyles.colors?.heading || undefined;
869
+ // Ensure heading color falls back to text if not provided
870
+ if (!tokens.colors.heading) {
871
+ tokens.colors.heading =
872
+ // Prefer explicit heading color if provided by Theme Editor
873
+ wpStyles.colors?.heading ||
874
+ // Then Theme Editor palette contrast (matches heading color choice in editor)
875
+ palette['contrast'] ||
876
+ // Then palette primary
877
+ palette['primary'] ||
878
+ // Then explicit primary fallback
879
+ wpStyles.colors?.primary ||
880
+ tokens.colors.text;
881
+ }
882
+ // Generate alternate and highlight colors from primary/background
883
+ if (tokens.colors.primary && tokens.colors.background) {
884
+ // Alternate: slightly darker/lighter than background
885
+ tokens.colors.alternate = adjustBrightness(tokens.colors.background, -0.05);
886
+ // Highlight: tinted with primary color
887
+ tokens.colors.highlight = blendColors(tokens.colors.background, tokens.colors.primary, 0.1);
888
+ }
889
+ return tokens;
890
+ }
891
+
892
+ const THEME_STYLE_ID = 'dstyler-theme-vars';
893
+ function tokensToCSS(tokens) {
894
+ return `
895
+ --dstyler-color-primary: ${tokens.colors.primary};
896
+ --dstyler-color-secondary: ${tokens.colors.secondary};
897
+ --dstyler-color-background: ${tokens.colors.background};
898
+ --dstyler-color-text: ${tokens.colors.text};
899
+ --dstyler-color-heading: ${tokens.colors.heading || tokens.colors.text};
900
+ --dstyler-color-default: ${tokens.colors.default};
901
+ --dstyler-color-alternate: ${tokens.colors.alternate};
902
+ --dstyler-color-highlight: ${tokens.colors.highlight};
903
+ --dstyler-spacing-sm: ${tokens.spacing.sm}px;
904
+ --dstyler-spacing-md: ${tokens.spacing.md}px;
905
+ --dstyler-spacing-lg: ${tokens.spacing.lg}px;
906
+ --dstyler-spacing-xl: ${tokens.spacing.xl}px;
907
+ --dstyler-font-body: ${tokens.typography.body};
908
+ --dstyler-font-heading: ${tokens.typography.heading};
909
+ --dstyler-font-scale: ${tokens.typography.scale};
910
+ `;
911
+ }
912
+ function ensureStyleElement() {
913
+ if (typeof document === 'undefined')
914
+ return null;
915
+ let el = document.getElementById(THEME_STYLE_ID);
916
+ if (!el) {
917
+ el = document.createElement('style');
918
+ el.id = THEME_STYLE_ID;
919
+ document.head.appendChild(el);
920
+ }
921
+ return el;
922
+ }
923
+ /**
924
+ * Inject CSS variables from design tokens into :root
925
+ */
926
+ function injectCSSVariables(tokens) {
927
+ const el = ensureStyleElement();
928
+ if (!el)
929
+ return;
930
+ el.textContent = `:root { ${tokensToCSS(tokens)} }`;
931
+ }
932
+ /**
933
+ * Inject CSS variables for both light and dark themes.
934
+ * Light applies to :root, dark applies when [data-theme="dark"] is present.
935
+ */
936
+ function injectDualThemeCSS(light, dark) {
937
+ const el = ensureStyleElement();
938
+ if (!el)
939
+ return;
940
+ el.textContent = `
941
+ :root { ${tokensToCSS(light)} }
942
+ :root[data-theme="dark"] { ${tokensToCSS(dark)} }
943
+ `;
1032
944
  }
1033
945
 
1034
946
  /**
@@ -1037,6 +949,78 @@ function getResponsiveValue(mobile, tablet, desktop) {
1037
949
  * This file is part of the MarVAlt Open SDK.
1038
950
  * Copyright (c) 2025 Vibune Pty Ltd.
1039
951
  */
952
+ /**
953
+ * ThemeProvider - Provides design tokens to the application
954
+ *
955
+ * Priority order:
956
+ * 1. customTokens (highest priority - overrides everything)
957
+ * 2. WordPress styles (converted to tokens)
958
+ * 3. Default tokens (fallback)
959
+ */
960
+ const ThemeProvider = ({ children, wpStyles, customTokens, darkWpStyles, darkTokens, mode = 'light', }) => {
961
+ useEffect(() => {
962
+ // Light tokens: custom -> wpStyles -> default
963
+ const lightTokens = customTokens || convertWordPressToTokens(wpStyles);
964
+ // Dark tokens: provided -> wpStylesDark -> fallback to light
965
+ const resolvedDarkTokens = darkTokens || (darkWpStyles ? convertWordPressToTokens(darkWpStyles) : lightTokens);
966
+ if (mode === 'dark') {
967
+ injectDualThemeCSS(lightTokens, resolvedDarkTokens);
968
+ if (typeof document !== 'undefined') {
969
+ document.documentElement.setAttribute('data-theme', 'dark');
970
+ }
971
+ return;
972
+ }
973
+ if (mode === 'system') {
974
+ const prefersDark = typeof window !== 'undefined' &&
975
+ window.matchMedia &&
976
+ window.matchMedia('(prefers-color-scheme: dark)').matches;
977
+ injectDualThemeCSS(lightTokens, resolvedDarkTokens);
978
+ if (typeof document !== 'undefined') {
979
+ document.documentElement.setAttribute('data-theme', prefersDark ? 'dark' : 'light');
980
+ }
981
+ return;
982
+ }
983
+ // Default to light
984
+ injectDualThemeCSS(lightTokens, resolvedDarkTokens);
985
+ if (typeof document !== 'undefined') {
986
+ document.documentElement.setAttribute('data-theme', 'light');
987
+ }
988
+ }, [wpStyles, customTokens, darkWpStyles, darkTokens, mode]);
989
+ // Return children if provided, otherwise return null (theme still applies via useEffect)
990
+ if (children === undefined || children === null) {
991
+ return null;
992
+ }
993
+ return React.createElement(React.Fragment, null, children);
994
+ };
995
+
996
+ /**
997
+ * Check if a color is dark (for determining text color)
998
+ */
999
+ function isColorDark(color) {
1000
+ // Remove # if present
1001
+ const hex = color.replace('#', '');
1002
+ // Handle RGB/RGBA format
1003
+ if (color.startsWith('rgb')) {
1004
+ const match = color.match(/\d+/g);
1005
+ if (match && match.length >= 3) {
1006
+ const r = parseInt(match[0], 10);
1007
+ const g = parseInt(match[1], 10);
1008
+ const b = parseInt(match[2], 10);
1009
+ const brightness = (r * 299 + g * 587 + b * 114) / 1000;
1010
+ return brightness < 128;
1011
+ }
1012
+ }
1013
+ // Handle hex format
1014
+ if (hex.length === 6) {
1015
+ const r = parseInt(hex.substring(0, 2), 16);
1016
+ const g = parseInt(hex.substring(2, 4), 16);
1017
+ const b = parseInt(hex.substring(4, 6), 16);
1018
+ const brightness = (r * 299 + g * 587 + b * 114) / 1000;
1019
+ return brightness < 128;
1020
+ }
1021
+ // Default to light background
1022
+ return false;
1023
+ }
1040
1024
  /**
1041
1025
  * Create a colorMapper from design tokens and WordPress theme palette
1042
1026
  *
@@ -1063,7 +1047,9 @@ function getResponsiveValue(mobile, tablet, desktop) {
1063
1047
  */
1064
1048
  function createColorMapperFromTokens(tokens, themePalette, overrides) {
1065
1049
  // Debug logging
1066
- if (typeof window !== 'undefined' && typeof process !== 'undefined' && process.env.NODE_ENV === 'development') {
1050
+ if (typeof window !== 'undefined' &&
1051
+ typeof process !== 'undefined' &&
1052
+ process.env.NODE_ENV === 'development') {
1067
1053
  console.log('🎨 createColorMapperFromTokens - themePalette:', themePalette);
1068
1054
  console.log('🎨 createColorMapperFromTokens - tokens:', tokens);
1069
1055
  }
@@ -1080,7 +1066,9 @@ function createColorMapperFromTokens(tokens, themePalette, overrides) {
1080
1066
  const textColor = isDark ? 'text-white' : 'text-gray-900';
1081
1067
  // Include both bg (for background mapping) and text-[color] (for text mapping), plus contrast helper
1082
1068
  const result = `bg-[${color}] text-[${color}] ${textColor}`;
1083
- if (typeof window !== 'undefined' && typeof process !== 'undefined' && process.env.NODE_ENV === 'development') {
1069
+ if (typeof window !== 'undefined' &&
1070
+ typeof process !== 'undefined' &&
1071
+ process.env.NODE_ENV === 'development') {
1084
1072
  console.log(`🎨 Color mapper - ${wpColorName}:`, result, '(from theme palette)');
1085
1073
  }
1086
1074
  return result;
@@ -1088,53 +1076,25 @@ function createColorMapperFromTokens(tokens, themePalette, overrides) {
1088
1076
  // Fallback: Map WordPress theme colors to design tokens
1089
1077
  // Using Tailwind's arbitrary value syntax for hex colors
1090
1078
  const defaultMap = {
1091
- 'base': `bg-[${tokens.colors.background}] text-[${tokens.colors.text}]`,
1092
- 'background': `bg-[${tokens.colors.background}] text-[${tokens.colors.text}]`,
1093
- 'foreground': `text-[${tokens.colors.text}]`,
1094
- 'contrast': `bg-[${themePalette?.contrast || tokens.colors.text}] text-[${tokens.colors.background}]`,
1095
- 'primary': `bg-[${themePalette?.primary || tokens.colors.primary}] text-[${themePalette?.primary || tokens.colors.primary}]`,
1096
- 'secondary': `bg-[${themePalette?.secondary || tokens.colors.secondary}] text-[${themePalette?.secondary || tokens.colors.secondary}]`,
1097
- 'heading': `text-[${tokens.colors.heading || tokens.colors.text}]`,
1098
- 'accent': `bg-[${tokens.colors.highlight}] text-[${tokens.colors.highlight}]`,
1079
+ base: `bg-[${tokens.colors.background}] text-[${tokens.colors.text}]`,
1080
+ background: `bg-[${tokens.colors.background}] text-[${tokens.colors.text}]`,
1081
+ foreground: `text-[${tokens.colors.text}]`,
1082
+ contrast: `bg-[${themePalette?.contrast || tokens.colors.text}] text-[${tokens.colors.background}]`,
1083
+ primary: `bg-[${themePalette?.primary || tokens.colors.primary}] text-[${themePalette?.primary || tokens.colors.primary}]`,
1084
+ secondary: `bg-[${themePalette?.secondary || tokens.colors.secondary}] text-[${themePalette?.secondary || tokens.colors.secondary}]`,
1085
+ heading: `text-[${tokens.colors.heading || tokens.colors.text}]`,
1086
+ accent: `bg-[${tokens.colors.highlight}] text-[${tokens.colors.highlight}]`,
1099
1087
  'accent-1': `bg-[${themePalette?.['accent-1'] || tokens.colors.primary}] text-[${themePalette?.['accent-1'] || tokens.colors.primary}]`,
1100
1088
  'accent-2': `bg-[${themePalette?.['accent-2'] || tokens.colors.secondary}] text-[${themePalette?.['accent-2'] || tokens.colors.secondary}]`,
1101
1089
  'accent-3': `bg-[${themePalette?.['accent-3'] || tokens.colors.highlight}] text-[${themePalette?.['accent-3'] || tokens.colors.highlight}]`,
1102
1090
  'accent-4': `bg-[${themePalette?.['accent-4'] || tokens.colors.alternate}] text-[${themePalette?.['accent-4'] || tokens.colors.alternate}]`,
1103
1091
  'accent-5': `bg-[${themePalette?.['accent-5'] || tokens.colors.default}] text-[${themePalette?.['accent-5'] || tokens.colors.default}]`,
1104
1092
  'accent-6': `bg-[${themePalette?.['accent-6'] || themePalette?.primary || tokens.colors.primary}] text-[${themePalette?.['accent-6'] || themePalette?.primary || tokens.colors.primary}]`,
1105
- 'transparent': 'bg-transparent',
1093
+ transparent: 'bg-transparent',
1106
1094
  };
1107
1095
  return wpColorName ? defaultMap[wpColorName] || null : null;
1108
1096
  };
1109
1097
  }
1110
- /**
1111
- * Check if a color is dark (for determining text color)
1112
- */
1113
- function isColorDark(color) {
1114
- // Remove # if present
1115
- const hex = color.replace('#', '');
1116
- // Handle RGB/RGBA format
1117
- if (color.startsWith('rgb')) {
1118
- const match = color.match(/\d+/g);
1119
- if (match && match.length >= 3) {
1120
- const r = parseInt(match[0], 10);
1121
- const g = parseInt(match[1], 10);
1122
- const b = parseInt(match[2], 10);
1123
- const brightness = (r * 299 + g * 587 + b * 114) / 1000;
1124
- return brightness < 128;
1125
- }
1126
- }
1127
- // Handle hex format
1128
- if (hex.length === 6) {
1129
- const r = parseInt(hex.substring(0, 2), 16);
1130
- const g = parseInt(hex.substring(2, 4), 16);
1131
- const b = parseInt(hex.substring(4, 6), 16);
1132
- const brightness = (r * 299 + g * 587 + b * 114) / 1000;
1133
- return brightness < 128;
1134
- }
1135
- // Default to light background
1136
- return false;
1137
- }
1138
1098
  /**
1139
1099
  * Create a colorMapper with semantic Tailwind classes
1140
1100
  *
@@ -1162,9 +1122,9 @@ function createColorMapperWithSemanticClasses(tokens, overrides) {
1162
1122
  // Map WordPress theme colors to semantic Tailwind classes
1163
1123
  // Assumes your Tailwind config has primary, secondary, muted, etc. defined
1164
1124
  const defaultMap = {
1165
- 'base': 'bg-white',
1166
- 'contrast': 'bg-gray-900 text-white',
1167
- 'transparent': 'bg-transparent',
1125
+ base: 'bg-white',
1126
+ contrast: 'bg-gray-900 text-white',
1127
+ transparent: 'bg-transparent',
1168
1128
  'accent-1': 'bg-primary text-primary-foreground',
1169
1129
  'accent-2': 'bg-secondary text-secondary-foreground',
1170
1130
  'accent-3': 'bg-muted text-muted-foreground',
@@ -1176,5 +1136,23 @@ function createColorMapperWithSemanticClasses(tokens, overrides) {
1176
1136
  };
1177
1137
  }
1178
1138
 
1179
- export { AutoBlock, AutoSection, FooterMinimal, HeroDefault, SectionBase, SectionWave, StyledPage, ThemeProvider, convertWordPressToTokens, createColorMapperFromTokens, createColorMapperWithSemanticClasses, defaultTokens, detectSections, determineSectionStyle, getResponsiveValue, injectCSSVariables, injectDualThemeCSS, selectBlockRenderer, selectTemplate };
1139
+ /**
1140
+ * @license GPL-3.0-or-later
1141
+ *
1142
+ * This file is part of the MarVAlt Open SDK.
1143
+ * Copyright (c) 2025 Vibune Pty Ltd.
1144
+ */
1145
+ /**
1146
+ * Responsive utility functions
1147
+ */
1148
+ function getResponsiveValue(mobile, tablet, desktop) {
1149
+ if (!tablet && !desktop) {
1150
+ return typeof mobile === 'number' ? `${mobile}px` : mobile;
1151
+ }
1152
+ // For now, return mobile value
1153
+ // In the future, this could use CSS custom properties with media queries
1154
+ return typeof mobile === 'number' ? `${mobile}px` : mobile;
1155
+ }
1156
+
1157
+ export { AutoBlock, AutoSection, BlockButton, BlockForm, BlockImage, BlockText, FooterMinimal, HeroDefault, SectionBase, SectionWave, StyledPage, ThemeProvider, convertWordPressToTokens, createColorMapperFromTokens, createColorMapperWithSemanticClasses, defaultTokens, detectSections, determineSectionStyle, getResponsiveValue, injectCSSVariables, injectDualThemeCSS, selectBlockRenderer, selectTemplate };
1180
1158
  //# sourceMappingURL=index.esm.js.map