@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.
- package/dist/components/AutoBlock.d.ts +8 -0
- package/dist/components/AutoBlock.d.ts.map +1 -1
- package/dist/components/AutoSection.d.ts +4 -1
- package/dist/components/AutoSection.d.ts.map +1 -1
- package/dist/components/StyledPage.d.ts +6 -0
- package/dist/components/StyledPage.d.ts.map +1 -1
- package/dist/components/index.d.ts +1 -1
- package/dist/components/index.d.ts.map +1 -1
- package/dist/engine/detectSections.d.ts.map +1 -1
- package/dist/engine/index.d.ts.map +1 -1
- package/dist/engine/renderBlock.d.ts +0 -3
- package/dist/engine/renderBlock.d.ts.map +1 -1
- package/dist/engine/selectTemplate.d.ts.map +1 -1
- package/dist/index.d.ts +159 -90
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +478 -500
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +481 -499
- package/dist/index.js.map +1 -1
- package/dist/providers/ThemeProvider.d.ts.map +1 -1
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/templates/FooterMinimal.d.ts.map +1 -1
- package/dist/templates/HeroDefault.d.ts.map +1 -1
- package/dist/templates/SectionBase.d.ts.map +1 -1
- package/dist/templates/SectionWave.d.ts.map +1 -1
- package/dist/templates/blocks/BlockButton.d.ts +6 -2
- package/dist/templates/blocks/BlockButton.d.ts.map +1 -1
- package/dist/templates/blocks/BlockForm.d.ts +6 -2
- package/dist/templates/blocks/BlockForm.d.ts.map +1 -1
- package/dist/templates/blocks/BlockImage.d.ts +6 -2
- package/dist/templates/blocks/BlockImage.d.ts.map +1 -1
- package/dist/templates/blocks/BlockText.d.ts +6 -2
- package/dist/templates/blocks/BlockText.d.ts.map +1 -1
- package/dist/templates/blocks/index.d.ts.map +1 -1
- package/dist/templates/index.d.ts +1 -0
- package/dist/templates/index.d.ts.map +1 -1
- package/dist/tokens/css-vars.d.ts.map +1 -1
- package/dist/tokens/index.d.ts.map +1 -1
- package/dist/tokens/tokens.d.ts.map +1 -1
- package/dist/tokens/wordpress-to-tokens.d.ts.map +1 -1
- package/dist/types/block.d.ts +2 -0
- package/dist/types/block.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/section.d.ts.map +1 -1
- package/dist/types/theme.d.ts.map +1 -1
- package/dist/utils/createColorMapper.d.ts.map +1 -1
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/responsive.d.ts.map +1 -1
- package/package.json +52 -69
- 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
|
-
*
|
|
652
|
-
*
|
|
653
|
-
*
|
|
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
|
-
*
|
|
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
|
|
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
|
|
664
|
-
if (
|
|
665
|
-
return '
|
|
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
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
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
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
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
|
-
|
|
872
|
-
|
|
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
|
-
|
|
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
|
|
747
|
+
return jsxRuntimeExports.jsx(HeroDefault, { section: section, children: renderBlocks() });
|
|
921
748
|
case 'FooterMinimal':
|
|
922
|
-
return
|
|
749
|
+
return jsxRuntimeExports.jsx(FooterMinimal, { section: section, children: renderBlocks() });
|
|
923
750
|
default:
|
|
924
|
-
return
|
|
751
|
+
return jsxRuntimeExports.jsx(SectionBase, { section: section, children: renderBlocks() });
|
|
925
752
|
}
|
|
926
753
|
};
|
|
927
754
|
|
|
928
755
|
/**
|
|
929
|
-
*
|
|
756
|
+
* StyledPage - Main entry point for dstyler
|
|
930
757
|
*
|
|
931
|
-
*
|
|
932
|
-
*
|
|
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(
|
|
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
|
-
*
|
|
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
|
-
*
|
|
813
|
+
* Blend two colors
|
|
1024
814
|
*/
|
|
1025
|
-
function
|
|
1026
|
-
|
|
1027
|
-
|
|
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
|
-
|
|
1030
|
-
//
|
|
1031
|
-
|
|
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' &&
|
|
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' &&
|
|
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
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
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
|
-
|
|
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
|