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