@marvalt/dstyler 0.1.19 → 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 -502
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +481 -501
- 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,240 +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
|
-
// heading handled below to allow palette fallback
|
|
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
|
-
// Explicit heading override (may be undefined/empty), then fallback below
|
|
73
|
-
tokens.colors.heading = wpStyles.colors?.heading || undefined;
|
|
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
|
-
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
3
|
var jsxRuntime = {exports: {}};
|
|
239
4
|
|
|
240
5
|
var reactJsxRuntime_production = {};
|
|
@@ -650,21 +415,80 @@ if (process.env.NODE_ENV === 'production') {
|
|
|
650
415
|
var jsxRuntimeExports = jsxRuntime.exports;
|
|
651
416
|
|
|
652
417
|
/**
|
|
653
|
-
*
|
|
654
|
-
*
|
|
655
|
-
*
|
|
656
|
-
* 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
|
|
657
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
|
+
}
|
|
658
447
|
/**
|
|
659
|
-
*
|
|
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
|
|
660
453
|
*/
|
|
661
|
-
function
|
|
662
|
-
const block = section.block;
|
|
663
|
-
const attrs = block.attributes || {};
|
|
454
|
+
function determineSectionStyle(section, previousStyle) {
|
|
664
455
|
const className = section.customClass?.toLowerCase() || '';
|
|
665
|
-
// Check for
|
|
666
|
-
if (
|
|
667
|
-
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';
|
|
668
492
|
}
|
|
669
493
|
// Check for footer (could be detected by block name or class)
|
|
670
494
|
if (className.includes('footer') || block.name === 'core/footer') {
|
|
@@ -678,101 +502,6 @@ function selectTemplate(section) {
|
|
|
678
502
|
return 'SectionBase';
|
|
679
503
|
}
|
|
680
504
|
|
|
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
505
|
/**
|
|
777
506
|
* Select block renderer based on block type
|
|
778
507
|
*/
|
|
@@ -793,7 +522,7 @@ function selectBlockRenderer(block) {
|
|
|
793
522
|
case 'core/shortcode':
|
|
794
523
|
// Check if it's a form shortcode
|
|
795
524
|
const attrs = block.attributes || {};
|
|
796
|
-
const content = attrs.content || attrs.html || '';
|
|
525
|
+
const content = (attrs.content || attrs.html || '');
|
|
797
526
|
if (content.includes('[gravityform') || content.includes('[mauticform')) {
|
|
798
527
|
return 'BlockForm';
|
|
799
528
|
}
|
|
@@ -805,7 +534,7 @@ function selectBlockRenderer(block) {
|
|
|
805
534
|
|
|
806
535
|
const BlockText = ({ block, className }) => {
|
|
807
536
|
const attrs = block.attributes || {};
|
|
808
|
-
const content = attrs.content || attrs.text || '';
|
|
537
|
+
const content = (attrs.content || attrs.text || '');
|
|
809
538
|
const tagName = block.name === 'core/heading'
|
|
810
539
|
? `h${attrs.level || 2}`
|
|
811
540
|
: 'p';
|
|
@@ -825,40 +554,38 @@ const BlockText = ({ block, className }) => {
|
|
|
825
554
|
|
|
826
555
|
const BlockImage = ({ block, className }) => {
|
|
827
556
|
const attrs = block.attributes || {};
|
|
828
|
-
const url = attrs.url || attrs.sourceUrl || '';
|
|
829
|
-
const alt = attrs.alt || attrs.altText || '';
|
|
557
|
+
const url = (attrs.url || attrs.sourceUrl || '');
|
|
558
|
+
const alt = (attrs.alt || attrs.altText || '');
|
|
830
559
|
const width = attrs.width;
|
|
831
560
|
const height = attrs.height;
|
|
832
561
|
if (!url)
|
|
833
562
|
return null;
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
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" }));
|
|
841
569
|
};
|
|
842
570
|
|
|
843
571
|
const BlockButton = ({ block, className }) => {
|
|
844
572
|
const attrs = block.attributes || {};
|
|
845
|
-
const text = attrs.text || attrs.label || 'Button';
|
|
846
|
-
const url = attrs.url || attrs.linkUrl || '#';
|
|
573
|
+
const text = (attrs.text || attrs.label || 'Button');
|
|
574
|
+
const url = (attrs.url || attrs.linkUrl || '#');
|
|
847
575
|
const isExternal = typeof window !== 'undefined'
|
|
848
576
|
? url.startsWith('http') && !url.includes(window.location.hostname)
|
|
849
577
|
: url.startsWith('http');
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
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) => {
|
|
862
589
|
e.currentTarget.style.opacity = '0.9';
|
|
863
590
|
}, onMouseLeave: (e) => {
|
|
864
591
|
e.currentTarget.style.opacity = '1';
|
|
@@ -867,16 +594,22 @@ const BlockButton = ({ block, className }) => {
|
|
|
867
594
|
|
|
868
595
|
const BlockForm = ({ block, className }) => {
|
|
869
596
|
const attrs = block.attributes || {};
|
|
870
|
-
const content = attrs.content || attrs.html || '';
|
|
597
|
+
const content = (attrs.content || attrs.html || '');
|
|
871
598
|
// For now, just render the HTML content
|
|
872
599
|
// In the future, this could parse and render using Gravity Forms or Mautic components
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
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 } }));
|
|
877
603
|
};
|
|
878
604
|
|
|
879
|
-
|
|
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 }) => {
|
|
880
613
|
// If registry is provided, use it for rendering (integrates with wparser)
|
|
881
614
|
if (registry && registry.renderers[block.name]) {
|
|
882
615
|
const Renderer = registry.renderers[block.name];
|
|
@@ -886,19 +619,111 @@ const AutoBlock = ({ block, registry }) => {
|
|
|
886
619
|
const rendererName = selectBlockRenderer(block);
|
|
887
620
|
switch (rendererName) {
|
|
888
621
|
case 'BlockText':
|
|
889
|
-
return jsxRuntimeExports.jsx(BlockText, { block: block });
|
|
622
|
+
return jsxRuntimeExports.jsx(BlockText, { block: block, className: className });
|
|
890
623
|
case 'BlockImage':
|
|
891
|
-
return jsxRuntimeExports.jsx(BlockImage, { block: block });
|
|
624
|
+
return jsxRuntimeExports.jsx(BlockImage, { block: block, className: className });
|
|
892
625
|
case 'BlockButton':
|
|
893
|
-
return jsxRuntimeExports.jsx(BlockButton, { block: block });
|
|
626
|
+
return jsxRuntimeExports.jsx(BlockButton, { block: block, className: className });
|
|
894
627
|
case 'BlockForm':
|
|
895
|
-
return jsxRuntimeExports.jsx(BlockForm, { block: block });
|
|
628
|
+
return jsxRuntimeExports.jsx(BlockForm, { block: block, className: className });
|
|
896
629
|
default:
|
|
897
630
|
// Fallback: render block name or content
|
|
898
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)] }) }));
|
|
899
632
|
}
|
|
900
633
|
};
|
|
901
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
|
+
*/
|
|
902
727
|
const AutoSection = ({ section, registry }) => {
|
|
903
728
|
const templateName = selectTemplate(section);
|
|
904
729
|
// Render blocks using AutoBlock or registry
|
|
@@ -919,85 +744,20 @@ const AutoSection = ({ section, registry }) => {
|
|
|
919
744
|
return (jsxRuntimeExports.jsx(SectionWave, { section: section, waveTop: waveTop, waveBottom: waveBottom, children: renderBlocks() }));
|
|
920
745
|
}
|
|
921
746
|
case 'HeroDefault':
|
|
922
|
-
return
|
|
747
|
+
return jsxRuntimeExports.jsx(HeroDefault, { section: section, children: renderBlocks() });
|
|
923
748
|
case 'FooterMinimal':
|
|
924
|
-
return
|
|
749
|
+
return jsxRuntimeExports.jsx(FooterMinimal, { section: section, children: renderBlocks() });
|
|
925
750
|
default:
|
|
926
|
-
return
|
|
751
|
+
return jsxRuntimeExports.jsx(SectionBase, { section: section, children: renderBlocks() });
|
|
927
752
|
}
|
|
928
753
|
};
|
|
929
754
|
|
|
930
755
|
/**
|
|
931
|
-
*
|
|
756
|
+
* StyledPage - Main entry point for dstyler
|
|
932
757
|
*
|
|
933
|
-
*
|
|
934
|
-
*
|
|
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
|
|
758
|
+
* Detects sections from WordPress blocks and applies alternating styles
|
|
759
|
+
* Integrates with wparser's registry for block rendering
|
|
940
760
|
*/
|
|
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
761
|
const StyledPage = ({ page, registry }) => {
|
|
1002
762
|
const blocks = page.blocks || [];
|
|
1003
763
|
// Detect sections from blocks
|
|
@@ -1012,25 +772,175 @@ const StyledPage = ({ page, registry }) => {
|
|
|
1012
772
|
style,
|
|
1013
773
|
};
|
|
1014
774
|
});
|
|
1015
|
-
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
|
+
},
|
|
1016
800
|
};
|
|
1017
801
|
|
|
1018
802
|
/**
|
|
1019
|
-
*
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
803
|
+
* Adjust brightness of a hex color
|
|
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
|
+
}
|
|
812
|
+
/**
|
|
813
|
+
* Blend two colors
|
|
1023
814
|
*/
|
|
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
|
+
}
|
|
1024
835
|
/**
|
|
1025
|
-
*
|
|
836
|
+
* Convert WordPress theme styles to design tokens
|
|
1026
837
|
*/
|
|
1027
|
-
function
|
|
1028
|
-
if (!
|
|
1029
|
-
return
|
|
838
|
+
function convertWordPressToTokens(wpStyles) {
|
|
839
|
+
if (!wpStyles) {
|
|
840
|
+
return defaultTokens;
|
|
1030
841
|
}
|
|
1031
|
-
|
|
1032
|
-
//
|
|
1033
|
-
|
|
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
|
+
`;
|
|
1034
944
|
}
|
|
1035
945
|
|
|
1036
946
|
/**
|
|
@@ -1039,6 +949,78 @@ function getResponsiveValue(mobile, tablet, desktop) {
|
|
|
1039
949
|
* This file is part of the MarVAlt Open SDK.
|
|
1040
950
|
* Copyright (c) 2025 Vibune Pty Ltd.
|
|
1041
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
|
+
}
|
|
1042
1024
|
/**
|
|
1043
1025
|
* Create a colorMapper from design tokens and WordPress theme palette
|
|
1044
1026
|
*
|
|
@@ -1065,7 +1047,9 @@ function getResponsiveValue(mobile, tablet, desktop) {
|
|
|
1065
1047
|
*/
|
|
1066
1048
|
function createColorMapperFromTokens(tokens, themePalette, overrides) {
|
|
1067
1049
|
// Debug logging
|
|
1068
|
-
if (typeof window !== 'undefined' &&
|
|
1050
|
+
if (typeof window !== 'undefined' &&
|
|
1051
|
+
typeof process !== 'undefined' &&
|
|
1052
|
+
process.env.NODE_ENV === 'development') {
|
|
1069
1053
|
console.log('🎨 createColorMapperFromTokens - themePalette:', themePalette);
|
|
1070
1054
|
console.log('🎨 createColorMapperFromTokens - tokens:', tokens);
|
|
1071
1055
|
}
|
|
@@ -1082,7 +1066,9 @@ function createColorMapperFromTokens(tokens, themePalette, overrides) {
|
|
|
1082
1066
|
const textColor = isDark ? 'text-white' : 'text-gray-900';
|
|
1083
1067
|
// Include both bg (for background mapping) and text-[color] (for text mapping), plus contrast helper
|
|
1084
1068
|
const result = `bg-[${color}] text-[${color}] ${textColor}`;
|
|
1085
|
-
if (typeof window !== 'undefined' &&
|
|
1069
|
+
if (typeof window !== 'undefined' &&
|
|
1070
|
+
typeof process !== 'undefined' &&
|
|
1071
|
+
process.env.NODE_ENV === 'development') {
|
|
1086
1072
|
console.log(`🎨 Color mapper - ${wpColorName}:`, result, '(from theme palette)');
|
|
1087
1073
|
}
|
|
1088
1074
|
return result;
|
|
@@ -1090,53 +1076,25 @@ function createColorMapperFromTokens(tokens, themePalette, overrides) {
|
|
|
1090
1076
|
// Fallback: Map WordPress theme colors to design tokens
|
|
1091
1077
|
// Using Tailwind's arbitrary value syntax for hex colors
|
|
1092
1078
|
const defaultMap = {
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
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}]`,
|
|
1101
1087
|
'accent-1': `bg-[${themePalette?.['accent-1'] || tokens.colors.primary}] text-[${themePalette?.['accent-1'] || tokens.colors.primary}]`,
|
|
1102
1088
|
'accent-2': `bg-[${themePalette?.['accent-2'] || tokens.colors.secondary}] text-[${themePalette?.['accent-2'] || tokens.colors.secondary}]`,
|
|
1103
1089
|
'accent-3': `bg-[${themePalette?.['accent-3'] || tokens.colors.highlight}] text-[${themePalette?.['accent-3'] || tokens.colors.highlight}]`,
|
|
1104
1090
|
'accent-4': `bg-[${themePalette?.['accent-4'] || tokens.colors.alternate}] text-[${themePalette?.['accent-4'] || tokens.colors.alternate}]`,
|
|
1105
1091
|
'accent-5': `bg-[${themePalette?.['accent-5'] || tokens.colors.default}] text-[${themePalette?.['accent-5'] || tokens.colors.default}]`,
|
|
1106
1092
|
'accent-6': `bg-[${themePalette?.['accent-6'] || themePalette?.primary || tokens.colors.primary}] text-[${themePalette?.['accent-6'] || themePalette?.primary || tokens.colors.primary}]`,
|
|
1107
|
-
|
|
1093
|
+
transparent: 'bg-transparent',
|
|
1108
1094
|
};
|
|
1109
1095
|
return wpColorName ? defaultMap[wpColorName] || null : null;
|
|
1110
1096
|
};
|
|
1111
1097
|
}
|
|
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
1098
|
/**
|
|
1141
1099
|
* Create a colorMapper with semantic Tailwind classes
|
|
1142
1100
|
*
|
|
@@ -1164,9 +1122,9 @@ function createColorMapperWithSemanticClasses(tokens, overrides) {
|
|
|
1164
1122
|
// Map WordPress theme colors to semantic Tailwind classes
|
|
1165
1123
|
// Assumes your Tailwind config has primary, secondary, muted, etc. defined
|
|
1166
1124
|
const defaultMap = {
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1125
|
+
base: 'bg-white',
|
|
1126
|
+
contrast: 'bg-gray-900 text-white',
|
|
1127
|
+
transparent: 'bg-transparent',
|
|
1170
1128
|
'accent-1': 'bg-primary text-primary-foreground',
|
|
1171
1129
|
'accent-2': 'bg-secondary text-secondary-foreground',
|
|
1172
1130
|
'accent-3': 'bg-muted text-muted-foreground',
|
|
@@ -1178,5 +1136,23 @@ function createColorMapperWithSemanticClasses(tokens, overrides) {
|
|
|
1178
1136
|
};
|
|
1179
1137
|
}
|
|
1180
1138
|
|
|
1181
|
-
|
|
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 };
|
|
1182
1158
|
//# sourceMappingURL=index.esm.js.map
|