cf-pagetree-parser 1.0.6 → 1.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/cf-pagetree-parser.js +101 -18
- package/package.json +2 -2
- package/src/index.js +2 -0
- package/src/parsers/button.js +10 -3
- package/src/parsers/interactive.js +2 -9
- package/src/parsers/text.js +34 -5
- package/src/styles.js +55 -1
package/README.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Parse FunnelWind HTML to ClickFunnels PageTree JSON.
|
|
4
4
|
|
|
5
|
+
**Requires [cf-elements](https://www.npmjs.com/package/cf-elements)** - This parser works on the rendered HTML output from cf-elements. The cf-elements package renders FunnelWind custom elements (like `<cf-section>`, `<cf-headline>`, `<cf-button>`) into the DOM structure that this parser reads.
|
|
6
|
+
|
|
5
7
|
## Installation
|
|
6
8
|
|
|
7
9
|
```bash
|
|
@@ -420,6 +420,34 @@ function parseHtmlToTextNodes(html, defaultLinkColor = null) {
|
|
|
420
420
|
* ============================================================================
|
|
421
421
|
*/
|
|
422
422
|
|
|
423
|
+
/**
|
|
424
|
+
* Shadow preset names to CSS values (matches cf-elements SHADOWS)
|
|
425
|
+
*/
|
|
426
|
+
const SHADOW_NAMES = {
|
|
427
|
+
none: 'none',
|
|
428
|
+
sm: '0 1px 2px rgba(0,0,0,0.05)',
|
|
429
|
+
default: '0 1px 3px rgba(0,0,0,0.1)',
|
|
430
|
+
md: '0 4px 6px rgba(0,0,0,0.1)',
|
|
431
|
+
lg: '0 10px 15px rgba(0,0,0,0.1)',
|
|
432
|
+
xl: '0 20px 25px rgba(0,0,0,0.1)',
|
|
433
|
+
'2xl': '0 25px 50px rgba(0,0,0,0.25)',
|
|
434
|
+
};
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Radius preset names to CSS values (matches cf-elements RADIUS)
|
|
438
|
+
*/
|
|
439
|
+
const RADIUS_NAMES = {
|
|
440
|
+
none: '0',
|
|
441
|
+
sm: '4px',
|
|
442
|
+
default: '8px',
|
|
443
|
+
md: '12px',
|
|
444
|
+
lg: '16px',
|
|
445
|
+
xl: '20px',
|
|
446
|
+
'2xl': '24px',
|
|
447
|
+
'3xl': '32px',
|
|
448
|
+
full: '9999px',
|
|
449
|
+
};
|
|
450
|
+
|
|
423
451
|
/**
|
|
424
452
|
* Shadow presets mapping (from inline shadow to CF params)
|
|
425
453
|
*/
|
|
@@ -447,11 +475,20 @@ const SHADOW_PRESETS = {
|
|
|
447
475
|
|
|
448
476
|
/**
|
|
449
477
|
* Parse box-shadow value to CF params
|
|
478
|
+
* Handles both preset names (sm, md, lg, xl) and CSS shadow strings
|
|
450
479
|
*/
|
|
451
480
|
function parseShadow(shadowValue) {
|
|
452
481
|
if (!shadowValue || shadowValue === 'none') return null;
|
|
453
482
|
|
|
454
|
-
// Check if it
|
|
483
|
+
// Check if it's a preset name first (e.g., "sm", "lg", "xl")
|
|
484
|
+
if (SHADOW_NAMES[shadowValue]) {
|
|
485
|
+
const resolvedShadow = SHADOW_NAMES[shadowValue];
|
|
486
|
+
if (resolvedShadow === 'none') return null;
|
|
487
|
+
// Now parse the resolved CSS value
|
|
488
|
+
return parseShadow(resolvedShadow);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// Check if it matches a preset CSS value
|
|
455
492
|
const normalized = shadowValue.replace(/\s+/g, ' ').trim();
|
|
456
493
|
if (SHADOW_PRESETS[normalized]) {
|
|
457
494
|
return SHADOW_PRESETS[normalized];
|
|
@@ -694,6 +731,23 @@ function parseBorderRadius(styles) {
|
|
|
694
731
|
return null;
|
|
695
732
|
}
|
|
696
733
|
|
|
734
|
+
/**
|
|
735
|
+
* Resolve radius value - handles both preset names (sm, md, lg) and CSS values
|
|
736
|
+
* Returns { value, unit } or null
|
|
737
|
+
*/
|
|
738
|
+
function resolveRadius(radiusValue) {
|
|
739
|
+
if (!radiusValue || radiusValue === 'none') return { value: 0, unit: 'px' };
|
|
740
|
+
|
|
741
|
+
// Check if it's a preset name first (e.g., "sm", "lg", "xl")
|
|
742
|
+
if (RADIUS_NAMES[radiusValue]) {
|
|
743
|
+
const resolvedRadius = RADIUS_NAMES[radiusValue];
|
|
744
|
+
return parseValueWithUnit(resolvedRadius);
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
// Otherwise parse as a CSS value
|
|
748
|
+
return parseValueWithUnit(radiusValue);
|
|
749
|
+
}
|
|
750
|
+
|
|
697
751
|
/**
|
|
698
752
|
* Convert font-weight string to numeric value
|
|
699
753
|
*/
|
|
@@ -1653,7 +1707,12 @@ function parseTextElement(
|
|
|
1653
1707
|
? parseFontFamily(fontAttr)
|
|
1654
1708
|
: parseFontFamily(textStyles["font-family"]);
|
|
1655
1709
|
|
|
1656
|
-
// Get color
|
|
1710
|
+
// Get color with proper inheritance chain:
|
|
1711
|
+
// 1. Element's own data-color attribute
|
|
1712
|
+
// 2. Inline style color
|
|
1713
|
+
// 3. Walk up parent containers checking for data-color (cf-flex, cf-col, cf-row, cf-section)
|
|
1714
|
+
// 4. cf-page text-color attribute
|
|
1715
|
+
// 5. Default fallback
|
|
1657
1716
|
const colorAttr = element.getAttribute("data-color");
|
|
1658
1717
|
let color;
|
|
1659
1718
|
if (colorAttr) {
|
|
@@ -1661,10 +1720,34 @@ function parseTextElement(
|
|
|
1661
1720
|
} else if (textStyles.color) {
|
|
1662
1721
|
color = normalizeColor(textStyles.color);
|
|
1663
1722
|
} else {
|
|
1664
|
-
//
|
|
1665
|
-
|
|
1666
|
-
const
|
|
1667
|
-
|
|
1723
|
+
// Walk up the DOM tree checking for data-color on parent containers
|
|
1724
|
+
// Check cf-flex, cf-col, cf-row, cf-section in order (closest first)
|
|
1725
|
+
const containerSelectors = [
|
|
1726
|
+
'[data-type="FlexContainer/V1"]',
|
|
1727
|
+
'[data-type="FlexContainer/V2"]',
|
|
1728
|
+
'[data-type="ColContainer/V1"]',
|
|
1729
|
+
'[data-type="RowContainer/V1"]',
|
|
1730
|
+
'[data-type="SectionContainer/V1"]',
|
|
1731
|
+
];
|
|
1732
|
+
|
|
1733
|
+
let inheritedColor = null;
|
|
1734
|
+
for (const selector of containerSelectors) {
|
|
1735
|
+
const parent = element.closest(selector);
|
|
1736
|
+
const parentColor = parent?.getAttribute("data-color");
|
|
1737
|
+
if (parentColor) {
|
|
1738
|
+
inheritedColor = normalizeColor(parentColor);
|
|
1739
|
+
break;
|
|
1740
|
+
}
|
|
1741
|
+
}
|
|
1742
|
+
|
|
1743
|
+
if (inheritedColor) {
|
|
1744
|
+
color = inheritedColor;
|
|
1745
|
+
} else {
|
|
1746
|
+
// Fall back to page-level color from ContentNode
|
|
1747
|
+
const contentNode = element.closest('[data-type="ContentNode"]');
|
|
1748
|
+
const pageColor = contentNode?.getAttribute("data-color") || contentNode?.getAttribute("data-text-color");
|
|
1749
|
+
color = pageColor ? normalizeColor(pageColor) : "#000000";
|
|
1750
|
+
}
|
|
1668
1751
|
}
|
|
1669
1752
|
|
|
1670
1753
|
const alignAttr = element.getAttribute("data-align");
|
|
@@ -1928,9 +2011,10 @@ function parseButton(element, parentId, index) {
|
|
|
1928
2011
|
const paddingVertical = pyAttr ? parseValueWithUnit(pyAttr) : parseValueWithUnit(anchorStyles['padding-top'] || '16px');
|
|
1929
2012
|
|
|
1930
2013
|
// Border and corners - data attributes first, then inline styles
|
|
2014
|
+
// Use resolveRadius to handle preset names like "lg", "xl", etc.
|
|
1931
2015
|
const roundedAttr = element.getAttribute('data-rounded');
|
|
1932
2016
|
const borderRadius = roundedAttr
|
|
1933
|
-
?
|
|
2017
|
+
? resolveRadius(roundedAttr)
|
|
1934
2018
|
: parseBorderRadius(anchorStyles);
|
|
1935
2019
|
|
|
1936
2020
|
const borderColorAttr = element.getAttribute('data-border-color');
|
|
@@ -1980,9 +2064,12 @@ function parseButton(element, parentId, index) {
|
|
|
1980
2064
|
const fullWidth = element.getAttribute('data-full-width') === 'true';
|
|
1981
2065
|
|
|
1982
2066
|
// Build button selector - always include padding params
|
|
2067
|
+
const hasBorder = borderWidth && borderWidth.value > 0;
|
|
1983
2068
|
const buttonSelector = {
|
|
1984
2069
|
attrs: {
|
|
1985
2070
|
style: {},
|
|
2071
|
+
'data-skip-shadow-settings': shadow ? 'false' : 'true',
|
|
2072
|
+
'data-skip-corners-settings': borderRadius ? 'false' : 'true',
|
|
1986
2073
|
},
|
|
1987
2074
|
params: {
|
|
1988
2075
|
'--style-padding-horizontal': paddingHorizontal ? paddingHorizontal.value : 32,
|
|
@@ -1993,6 +2080,7 @@ function parseButton(element, parentId, index) {
|
|
|
1993
2080
|
'--style-border-color': borderColor || 'transparent',
|
|
1994
2081
|
'--style-border-width': borderWidth ? borderWidth.value : 0,
|
|
1995
2082
|
'--style-border-width--unit': borderWidth ? borderWidth.unit : 'px',
|
|
2083
|
+
'--style-border-style': hasBorder ? 'solid' : 'none',
|
|
1996
2084
|
},
|
|
1997
2085
|
};
|
|
1998
2086
|
|
|
@@ -2097,9 +2185,9 @@ function parseButton(element, parentId, index) {
|
|
|
2097
2185
|
node.selectors['.elButton'].params['border-radius--unit'] = borderRadius.unit;
|
|
2098
2186
|
}
|
|
2099
2187
|
|
|
2100
|
-
// Apply shadow
|
|
2188
|
+
// Apply shadow
|
|
2101
2189
|
if (shadow) {
|
|
2102
|
-
|
|
2190
|
+
Object.assign(node.selectors['.elButton'].params, shadowToParams(shadow));
|
|
2103
2191
|
}
|
|
2104
2192
|
|
|
2105
2193
|
// Add subtext if present
|
|
@@ -3849,19 +3937,12 @@ function parseCountdown(element, parentId, index) {
|
|
|
3849
3937
|
const borderRadius = parseBorderRadius(containerStyles);
|
|
3850
3938
|
|
|
3851
3939
|
// Parse shadow from inline styles or data attribute
|
|
3940
|
+
// parseShadow() now handles preset names like "sm", "lg", "xl" automatically
|
|
3852
3941
|
let shadow = parseShadow(containerStyles['box-shadow']);
|
|
3853
3942
|
if (!shadow) {
|
|
3854
3943
|
const shadowAttr = element.getAttribute('data-shadow');
|
|
3855
3944
|
if (shadowAttr) {
|
|
3856
|
-
|
|
3857
|
-
const SHADOW_VALUES = {
|
|
3858
|
-
'sm': '0 1px 2px rgba(0,0,0,0.05)',
|
|
3859
|
-
'md': '0 4px 6px rgba(0,0,0,0.1)',
|
|
3860
|
-
'lg': '0 10px 15px rgba(0,0,0,0.1)',
|
|
3861
|
-
'xl': '0 20px 25px rgba(0,0,0,0.1)',
|
|
3862
|
-
'2xl': '0 25px 50px rgba(0,0,0,0.25)',
|
|
3863
|
-
};
|
|
3864
|
-
shadow = parseShadow(SHADOW_VALUES[shadowAttr] || shadowAttr);
|
|
3945
|
+
shadow = parseShadow(shadowAttr);
|
|
3865
3946
|
}
|
|
3866
3947
|
}
|
|
3867
3948
|
|
|
@@ -4385,6 +4466,7 @@ const PARSER_MAP = {
|
|
|
4385
4466
|
"ColContainer/V1": parseColContainer,
|
|
4386
4467
|
"ColInner/V1": parseColInner,
|
|
4387
4468
|
"FlexContainer/V1": parseFlexContainer,
|
|
4469
|
+
"FlexContainer/V2": parseFlexContainer,
|
|
4388
4470
|
"Headline/V1": parseHeadline,
|
|
4389
4471
|
"SubHeadline/V1": parseSubHeadline,
|
|
4390
4472
|
"Paragraph/V1": parseParagraph,
|
|
@@ -4435,6 +4517,7 @@ function createParseElement(elementIdMap) {
|
|
|
4435
4517
|
"RowContainer/V1",
|
|
4436
4518
|
"ColContainer/V1",
|
|
4437
4519
|
"FlexContainer/V1",
|
|
4520
|
+
"FlexContainer/V2",
|
|
4438
4521
|
];
|
|
4439
4522
|
|
|
4440
4523
|
let node;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cf-pagetree-parser",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"description": "Parse FunnelWind HTML to ClickFunnels PageTree JSON",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -28,6 +28,6 @@
|
|
|
28
28
|
"license": "MIT",
|
|
29
29
|
"repository": {
|
|
30
30
|
"type": "git",
|
|
31
|
-
"url": "https://github.com/
|
|
31
|
+
"url": "https://github.com/PrimeMoverHQ/BarnumPT-Builder.git"
|
|
32
32
|
}
|
|
33
33
|
}
|
package/src/index.js
CHANGED
|
@@ -63,6 +63,7 @@ const PARSER_MAP = {
|
|
|
63
63
|
"ColContainer/V1": parseColContainer,
|
|
64
64
|
"ColInner/V1": parseColInner,
|
|
65
65
|
"FlexContainer/V1": parseFlexContainer,
|
|
66
|
+
"FlexContainer/V2": parseFlexContainer,
|
|
66
67
|
"Headline/V1": parseHeadline,
|
|
67
68
|
"SubHeadline/V1": parseSubHeadline,
|
|
68
69
|
"Paragraph/V1": parseParagraph,
|
|
@@ -113,6 +114,7 @@ function createParseElement(elementIdMap) {
|
|
|
113
114
|
"RowContainer/V1",
|
|
114
115
|
"ColContainer/V1",
|
|
115
116
|
"FlexContainer/V1",
|
|
117
|
+
"FlexContainer/V2",
|
|
116
118
|
];
|
|
117
119
|
|
|
118
120
|
let node;
|
package/src/parsers/button.js
CHANGED
|
@@ -23,6 +23,8 @@ import {
|
|
|
23
23
|
spacingToAttrsAndParams,
|
|
24
24
|
parseBorderRadius,
|
|
25
25
|
parseShadow,
|
|
26
|
+
shadowToParams,
|
|
27
|
+
resolveRadius,
|
|
26
28
|
normalizeFontWeight,
|
|
27
29
|
parseTextAlign,
|
|
28
30
|
} from '../styles.js';
|
|
@@ -87,9 +89,10 @@ export function parseButton(element, parentId, index) {
|
|
|
87
89
|
const paddingVertical = pyAttr ? parseValueWithUnit(pyAttr) : parseValueWithUnit(anchorStyles['padding-top'] || '16px');
|
|
88
90
|
|
|
89
91
|
// Border and corners - data attributes first, then inline styles
|
|
92
|
+
// Use resolveRadius to handle preset names like "lg", "xl", etc.
|
|
90
93
|
const roundedAttr = element.getAttribute('data-rounded');
|
|
91
94
|
const borderRadius = roundedAttr
|
|
92
|
-
?
|
|
95
|
+
? resolveRadius(roundedAttr)
|
|
93
96
|
: parseBorderRadius(anchorStyles);
|
|
94
97
|
|
|
95
98
|
const borderColorAttr = element.getAttribute('data-border-color');
|
|
@@ -139,9 +142,12 @@ export function parseButton(element, parentId, index) {
|
|
|
139
142
|
const fullWidth = element.getAttribute('data-full-width') === 'true';
|
|
140
143
|
|
|
141
144
|
// Build button selector - always include padding params
|
|
145
|
+
const hasBorder = borderWidth && borderWidth.value > 0;
|
|
142
146
|
const buttonSelector = {
|
|
143
147
|
attrs: {
|
|
144
148
|
style: {},
|
|
149
|
+
'data-skip-shadow-settings': shadow ? 'false' : 'true',
|
|
150
|
+
'data-skip-corners-settings': borderRadius ? 'false' : 'true',
|
|
145
151
|
},
|
|
146
152
|
params: {
|
|
147
153
|
'--style-padding-horizontal': paddingHorizontal ? paddingHorizontal.value : 32,
|
|
@@ -152,6 +158,7 @@ export function parseButton(element, parentId, index) {
|
|
|
152
158
|
'--style-border-color': borderColor || 'transparent',
|
|
153
159
|
'--style-border-width': borderWidth ? borderWidth.value : 0,
|
|
154
160
|
'--style-border-width--unit': borderWidth ? borderWidth.unit : 'px',
|
|
161
|
+
'--style-border-style': hasBorder ? 'solid' : 'none',
|
|
155
162
|
},
|
|
156
163
|
};
|
|
157
164
|
|
|
@@ -256,9 +263,9 @@ export function parseButton(element, parentId, index) {
|
|
|
256
263
|
node.selectors['.elButton'].params['border-radius--unit'] = borderRadius.unit;
|
|
257
264
|
}
|
|
258
265
|
|
|
259
|
-
// Apply shadow
|
|
266
|
+
// Apply shadow
|
|
260
267
|
if (shadow) {
|
|
261
|
-
|
|
268
|
+
Object.assign(node.selectors['.elButton'].params, shadowToParams(shadow));
|
|
262
269
|
}
|
|
263
270
|
|
|
264
271
|
// Add subtext if present
|
|
@@ -308,19 +308,12 @@ export function parseCountdown(element, parentId, index) {
|
|
|
308
308
|
const borderRadius = parseBorderRadius(containerStyles);
|
|
309
309
|
|
|
310
310
|
// Parse shadow from inline styles or data attribute
|
|
311
|
+
// parseShadow() now handles preset names like "sm", "lg", "xl" automatically
|
|
311
312
|
let shadow = parseShadow(containerStyles['box-shadow']);
|
|
312
313
|
if (!shadow) {
|
|
313
314
|
const shadowAttr = element.getAttribute('data-shadow');
|
|
314
315
|
if (shadowAttr) {
|
|
315
|
-
|
|
316
|
-
const SHADOW_VALUES = {
|
|
317
|
-
'sm': '0 1px 2px rgba(0,0,0,0.05)',
|
|
318
|
-
'md': '0 4px 6px rgba(0,0,0,0.1)',
|
|
319
|
-
'lg': '0 10px 15px rgba(0,0,0,0.1)',
|
|
320
|
-
'xl': '0 20px 25px rgba(0,0,0,0.1)',
|
|
321
|
-
'2xl': '0 25px 50px rgba(0,0,0,0.25)',
|
|
322
|
-
};
|
|
323
|
-
shadow = parseShadow(SHADOW_VALUES[shadowAttr] || shadowAttr);
|
|
316
|
+
shadow = parseShadow(shadowAttr);
|
|
324
317
|
}
|
|
325
318
|
}
|
|
326
319
|
|
package/src/parsers/text.js
CHANGED
|
@@ -73,7 +73,12 @@ function parseTextElement(
|
|
|
73
73
|
? parseFontFamily(fontAttr)
|
|
74
74
|
: parseFontFamily(textStyles["font-family"]);
|
|
75
75
|
|
|
76
|
-
// Get color
|
|
76
|
+
// Get color with proper inheritance chain:
|
|
77
|
+
// 1. Element's own data-color attribute
|
|
78
|
+
// 2. Inline style color
|
|
79
|
+
// 3. Walk up parent containers checking for data-color (cf-flex, cf-col, cf-row, cf-section)
|
|
80
|
+
// 4. cf-page text-color attribute
|
|
81
|
+
// 5. Default fallback
|
|
77
82
|
const colorAttr = element.getAttribute("data-color");
|
|
78
83
|
let color;
|
|
79
84
|
if (colorAttr) {
|
|
@@ -81,10 +86,34 @@ function parseTextElement(
|
|
|
81
86
|
} else if (textStyles.color) {
|
|
82
87
|
color = normalizeColor(textStyles.color);
|
|
83
88
|
} else {
|
|
84
|
-
//
|
|
85
|
-
|
|
86
|
-
const
|
|
87
|
-
|
|
89
|
+
// Walk up the DOM tree checking for data-color on parent containers
|
|
90
|
+
// Check cf-flex, cf-col, cf-row, cf-section in order (closest first)
|
|
91
|
+
const containerSelectors = [
|
|
92
|
+
'[data-type="FlexContainer/V1"]',
|
|
93
|
+
'[data-type="FlexContainer/V2"]',
|
|
94
|
+
'[data-type="ColContainer/V1"]',
|
|
95
|
+
'[data-type="RowContainer/V1"]',
|
|
96
|
+
'[data-type="SectionContainer/V1"]',
|
|
97
|
+
];
|
|
98
|
+
|
|
99
|
+
let inheritedColor = null;
|
|
100
|
+
for (const selector of containerSelectors) {
|
|
101
|
+
const parent = element.closest(selector);
|
|
102
|
+
const parentColor = parent?.getAttribute("data-color");
|
|
103
|
+
if (parentColor) {
|
|
104
|
+
inheritedColor = normalizeColor(parentColor);
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (inheritedColor) {
|
|
110
|
+
color = inheritedColor;
|
|
111
|
+
} else {
|
|
112
|
+
// Fall back to page-level color from ContentNode
|
|
113
|
+
const contentNode = element.closest('[data-type="ContentNode"]');
|
|
114
|
+
const pageColor = contentNode?.getAttribute("data-color") || contentNode?.getAttribute("data-text-color");
|
|
115
|
+
color = pageColor ? normalizeColor(pageColor) : "#000000";
|
|
116
|
+
}
|
|
88
117
|
}
|
|
89
118
|
|
|
90
119
|
const alignAttr = element.getAttribute("data-align");
|
package/src/styles.js
CHANGED
|
@@ -10,6 +10,34 @@
|
|
|
10
10
|
|
|
11
11
|
import { parseValueWithUnit, normalizeColor } from './utils.js';
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Shadow preset names to CSS values (matches cf-elements SHADOWS)
|
|
15
|
+
*/
|
|
16
|
+
export const SHADOW_NAMES = {
|
|
17
|
+
none: 'none',
|
|
18
|
+
sm: '0 1px 2px rgba(0,0,0,0.05)',
|
|
19
|
+
default: '0 1px 3px rgba(0,0,0,0.1)',
|
|
20
|
+
md: '0 4px 6px rgba(0,0,0,0.1)',
|
|
21
|
+
lg: '0 10px 15px rgba(0,0,0,0.1)',
|
|
22
|
+
xl: '0 20px 25px rgba(0,0,0,0.1)',
|
|
23
|
+
'2xl': '0 25px 50px rgba(0,0,0,0.25)',
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Radius preset names to CSS values (matches cf-elements RADIUS)
|
|
28
|
+
*/
|
|
29
|
+
export const RADIUS_NAMES = {
|
|
30
|
+
none: '0',
|
|
31
|
+
sm: '4px',
|
|
32
|
+
default: '8px',
|
|
33
|
+
md: '12px',
|
|
34
|
+
lg: '16px',
|
|
35
|
+
xl: '20px',
|
|
36
|
+
'2xl': '24px',
|
|
37
|
+
'3xl': '32px',
|
|
38
|
+
full: '9999px',
|
|
39
|
+
};
|
|
40
|
+
|
|
13
41
|
/**
|
|
14
42
|
* Shadow presets mapping (from inline shadow to CF params)
|
|
15
43
|
*/
|
|
@@ -37,11 +65,20 @@ export const SHADOW_PRESETS = {
|
|
|
37
65
|
|
|
38
66
|
/**
|
|
39
67
|
* Parse box-shadow value to CF params
|
|
68
|
+
* Handles both preset names (sm, md, lg, xl) and CSS shadow strings
|
|
40
69
|
*/
|
|
41
70
|
export function parseShadow(shadowValue) {
|
|
42
71
|
if (!shadowValue || shadowValue === 'none') return null;
|
|
43
72
|
|
|
44
|
-
// Check if it
|
|
73
|
+
// Check if it's a preset name first (e.g., "sm", "lg", "xl")
|
|
74
|
+
if (SHADOW_NAMES[shadowValue]) {
|
|
75
|
+
const resolvedShadow = SHADOW_NAMES[shadowValue];
|
|
76
|
+
if (resolvedShadow === 'none') return null;
|
|
77
|
+
// Now parse the resolved CSS value
|
|
78
|
+
return parseShadow(resolvedShadow);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Check if it matches a preset CSS value
|
|
45
82
|
const normalized = shadowValue.replace(/\s+/g, ' ').trim();
|
|
46
83
|
if (SHADOW_PRESETS[normalized]) {
|
|
47
84
|
return SHADOW_PRESETS[normalized];
|
|
@@ -284,6 +321,23 @@ export function parseBorderRadius(styles) {
|
|
|
284
321
|
return null;
|
|
285
322
|
}
|
|
286
323
|
|
|
324
|
+
/**
|
|
325
|
+
* Resolve radius value - handles both preset names (sm, md, lg) and CSS values
|
|
326
|
+
* Returns { value, unit } or null
|
|
327
|
+
*/
|
|
328
|
+
export function resolveRadius(radiusValue) {
|
|
329
|
+
if (!radiusValue || radiusValue === 'none') return { value: 0, unit: 'px' };
|
|
330
|
+
|
|
331
|
+
// Check if it's a preset name first (e.g., "sm", "lg", "xl")
|
|
332
|
+
if (RADIUS_NAMES[radiusValue]) {
|
|
333
|
+
const resolvedRadius = RADIUS_NAMES[radiusValue];
|
|
334
|
+
return parseValueWithUnit(resolvedRadius);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// Otherwise parse as a CSS value
|
|
338
|
+
return parseValueWithUnit(radiusValue);
|
|
339
|
+
}
|
|
340
|
+
|
|
287
341
|
/**
|
|
288
342
|
* Convert font-weight string to numeric value
|
|
289
343
|
*/
|