cf-pagetree-parser 1.0.0
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 +79 -0
- package/dist/cf-pagetree-parser.js +5044 -0
- package/package.json +33 -0
- package/src/index.js +708 -0
- package/src/parsers/button.js +379 -0
- package/src/parsers/form.js +658 -0
- package/src/parsers/index.js +65 -0
- package/src/parsers/interactive.js +484 -0
- package/src/parsers/layout.js +788 -0
- package/src/parsers/list.js +359 -0
- package/src/parsers/media.js +376 -0
- package/src/parsers/placeholders.js +196 -0
- package/src/parsers/popup.js +133 -0
- package/src/parsers/text.js +278 -0
- package/src/styles.js +444 -0
- package/src/utils.js +402 -0
|
@@ -0,0 +1,658 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ============================================================================
|
|
3
|
+
* PAGETREE PARSER - Form Element Parsers
|
|
4
|
+
* ============================================================================
|
|
5
|
+
*
|
|
6
|
+
* Input/V1, TextArea/V1, SelectBox/V1, Checkbox/V1
|
|
7
|
+
*
|
|
8
|
+
* ============================================================================
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
generateId,
|
|
13
|
+
generateFractionalIndex,
|
|
14
|
+
parseInlineStyle,
|
|
15
|
+
parseValueWithUnit,
|
|
16
|
+
normalizeColor,
|
|
17
|
+
parseHtmlToTextNodes,
|
|
18
|
+
} from '../utils.js';
|
|
19
|
+
|
|
20
|
+
import {
|
|
21
|
+
parseSpacing,
|
|
22
|
+
spacingToAttrsAndParams,
|
|
23
|
+
parseBorderRadius,
|
|
24
|
+
parseBorder,
|
|
25
|
+
borderToParams,
|
|
26
|
+
parseShadow,
|
|
27
|
+
shadowToParams,
|
|
28
|
+
parseBackground,
|
|
29
|
+
} from '../styles.js';
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Parse Input/V1
|
|
33
|
+
*/
|
|
34
|
+
export function parseInput(element, parentId, index) {
|
|
35
|
+
const id = generateId();
|
|
36
|
+
|
|
37
|
+
const wrapperStyles = parseInlineStyle(element.getAttribute('style') || '');
|
|
38
|
+
const spacing = parseSpacing(wrapperStyles);
|
|
39
|
+
|
|
40
|
+
// Get input type from data attribute
|
|
41
|
+
const inputType = element.getAttribute('data-input-type') || 'email';
|
|
42
|
+
const inputName = element.getAttribute('data-input-name') || inputType;
|
|
43
|
+
const isRequired = element.getAttribute('data-required') === 'true';
|
|
44
|
+
const widthAttr = element.getAttribute('data-width');
|
|
45
|
+
const alignAttr = element.getAttribute('data-align') || 'center';
|
|
46
|
+
const placeholder = element.getAttribute('data-placeholder') || '';
|
|
47
|
+
const fontSizeAttr = element.getAttribute('data-font-size');
|
|
48
|
+
const colorAttr = element.getAttribute('data-color');
|
|
49
|
+
|
|
50
|
+
// Find the container div
|
|
51
|
+
const container = element.querySelector('div');
|
|
52
|
+
const containerStyles = container ? parseInlineStyle(container.getAttribute('style') || '') : {};
|
|
53
|
+
|
|
54
|
+
const background = parseBackground(containerStyles);
|
|
55
|
+
const border = parseBorder(containerStyles);
|
|
56
|
+
const borderRadius = parseBorderRadius(containerStyles);
|
|
57
|
+
const shadow = parseShadow(containerStyles['box-shadow']);
|
|
58
|
+
|
|
59
|
+
const paddingHorizontal = parseValueWithUnit(containerStyles['padding-left'] || '16px');
|
|
60
|
+
const paddingVertical = parseValueWithUnit(containerStyles['padding-top'] || '12px');
|
|
61
|
+
|
|
62
|
+
// Width percentage
|
|
63
|
+
const width = widthAttr ? parseFloat(widthAttr) : 100;
|
|
64
|
+
|
|
65
|
+
// Map align to CF format
|
|
66
|
+
const alignMap = { 'left': 'left', 'center': 'center', 'right': 'right' };
|
|
67
|
+
const marginAlign = alignMap[alignAttr] || 'center';
|
|
68
|
+
|
|
69
|
+
// Parse margin-top with default of 0
|
|
70
|
+
const marginTop = parseValueWithUnit(wrapperStyles['margin-top'] || '0px');
|
|
71
|
+
|
|
72
|
+
const node = {
|
|
73
|
+
type: 'Input/V1',
|
|
74
|
+
id,
|
|
75
|
+
version: 0,
|
|
76
|
+
parentId,
|
|
77
|
+
fractionalIndex: generateFractionalIndex(index),
|
|
78
|
+
attrs: {
|
|
79
|
+
'data-skip-shadow-settings': shadow ? 'false' : 'true',
|
|
80
|
+
type: inputType === 'phone_number' ? 'tel' : (inputType === 'email' ? 'email' : 'text'),
|
|
81
|
+
style: {
|
|
82
|
+
width,
|
|
83
|
+
'margin-top': marginTop.value,
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
params: {
|
|
87
|
+
label: placeholder,
|
|
88
|
+
labelType: 'on-border',
|
|
89
|
+
type: inputType,
|
|
90
|
+
'--style-background-color': background.color || '#ffffff',
|
|
91
|
+
'width--unit': '%',
|
|
92
|
+
'--style-margin-align': marginAlign,
|
|
93
|
+
'margin-top--unit': marginTop.unit,
|
|
94
|
+
},
|
|
95
|
+
selectors: {
|
|
96
|
+
'.elInput': {
|
|
97
|
+
attrs: {
|
|
98
|
+
name: inputName,
|
|
99
|
+
type: inputType,
|
|
100
|
+
className: isRequired ? 'required1' : 'required0',
|
|
101
|
+
style: {},
|
|
102
|
+
},
|
|
103
|
+
params: {
|
|
104
|
+
'font-size--unit': 'px',
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
'.inputHolder, .borderHolder': {
|
|
108
|
+
attrs: {
|
|
109
|
+
style: {
|
|
110
|
+
'padding-top': paddingVertical ? paddingVertical.value : 12,
|
|
111
|
+
'padding-bottom': paddingVertical ? paddingVertical.value : 12,
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
params: {
|
|
115
|
+
'--style-padding-horizontal': paddingHorizontal ? paddingHorizontal.value : 16,
|
|
116
|
+
'--style-padding-horizontal--unit': paddingHorizontal ? paddingHorizontal.unit : 'px',
|
|
117
|
+
'padding-top--unit': 'px',
|
|
118
|
+
'padding-bottom--unit': 'px',
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
'&.elFormItemWrapper, .inputHolder, .borderHolder': {
|
|
122
|
+
attrs: {
|
|
123
|
+
style: {},
|
|
124
|
+
'data-skip-corners-settings': borderRadius ? 'false' : 'true',
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
'.borderHolder': {
|
|
128
|
+
params: {
|
|
129
|
+
'--style-background-color': background.color || '#ffffff',
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
// Apply spacing
|
|
136
|
+
const { attrs: spacingAttrs, params: spacingParams } = spacingToAttrsAndParams(spacing);
|
|
137
|
+
Object.assign(node.attrs.style, spacingAttrs.style);
|
|
138
|
+
Object.assign(node.params, spacingParams);
|
|
139
|
+
|
|
140
|
+
// Apply border
|
|
141
|
+
if (border.width || border.style || border.color) {
|
|
142
|
+
Object.assign(node.selectors['.inputHolder, .borderHolder'].params, borderToParams(border));
|
|
143
|
+
} else {
|
|
144
|
+
// Default border
|
|
145
|
+
node.selectors['.inputHolder, .borderHolder'].params['--style-border-width'] = 1;
|
|
146
|
+
node.selectors['.inputHolder, .borderHolder'].params['--style-border-style'] = 'solid';
|
|
147
|
+
node.selectors['.inputHolder, .borderHolder'].params['--style-border-color'] = 'rgba(0, 0, 0, 0.2)';
|
|
148
|
+
node.selectors['.inputHolder, .borderHolder'].params['--style-border-width--unit'] = 'px';
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Apply border-radius
|
|
152
|
+
if (borderRadius) {
|
|
153
|
+
node.selectors['&.elFormItemWrapper, .inputHolder, .borderHolder'].attrs.style['border-radius'] = borderRadius.value;
|
|
154
|
+
node.selectors['&.elFormItemWrapper, .inputHolder, .borderHolder'].params = {
|
|
155
|
+
'border-radius--unit': borderRadius.unit,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Handle custom type
|
|
160
|
+
if (inputType === 'custom_type') {
|
|
161
|
+
node.selectors['.elInput'].attrs['data-custom-type'] = inputName;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Apply shadow
|
|
165
|
+
if (shadow) {
|
|
166
|
+
Object.assign(node.params, shadowToParams(shadow));
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Parse font-size - prefer data attribute, fallback to inline style
|
|
170
|
+
const inputEl = container ? container.querySelector('input') : null;
|
|
171
|
+
const inputStyles = inputEl ? parseInlineStyle(inputEl.getAttribute('style') || '') : {};
|
|
172
|
+
const fontSize = fontSizeAttr
|
|
173
|
+
? parseValueWithUnit(fontSizeAttr)
|
|
174
|
+
: parseValueWithUnit(inputStyles['font-size'] || '16px');
|
|
175
|
+
if (fontSize) {
|
|
176
|
+
node.selectors['.elInput'].attrs.style['font-size'] = fontSize.value;
|
|
177
|
+
node.selectors['.elInput'].params['font-size--unit'] = fontSize.unit;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Parse color - prefer data attribute, fallback to inline style
|
|
181
|
+
const textColor = colorAttr
|
|
182
|
+
? normalizeColor(colorAttr)
|
|
183
|
+
: (inputStyles.color ? normalizeColor(inputStyles.color) : null);
|
|
184
|
+
if (textColor) {
|
|
185
|
+
node.selectors['.elInput'].attrs.style.color = textColor;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return node;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Parse TextArea/V1
|
|
193
|
+
*/
|
|
194
|
+
export function parseTextArea(element, parentId, index) {
|
|
195
|
+
const id = generateId();
|
|
196
|
+
|
|
197
|
+
const wrapperStyles = parseInlineStyle(element.getAttribute('style') || '');
|
|
198
|
+
const spacing = parseSpacing(wrapperStyles);
|
|
199
|
+
|
|
200
|
+
const textareaName = element.getAttribute('data-textarea-name') || 'message';
|
|
201
|
+
const isRequired = element.getAttribute('data-required') === 'true';
|
|
202
|
+
const widthAttr = element.getAttribute('data-width');
|
|
203
|
+
const heightAttr = element.getAttribute('data-height');
|
|
204
|
+
const alignAttr = element.getAttribute('data-align') || 'center';
|
|
205
|
+
const placeholder = element.getAttribute('data-placeholder') || '';
|
|
206
|
+
const fontSizeAttr = element.getAttribute('data-font-size');
|
|
207
|
+
const colorAttr = element.getAttribute('data-color');
|
|
208
|
+
|
|
209
|
+
// Find the container div
|
|
210
|
+
const container = element.querySelector('div');
|
|
211
|
+
const containerStyles = container ? parseInlineStyle(container.getAttribute('style') || '') : {};
|
|
212
|
+
|
|
213
|
+
const background = parseBackground(containerStyles);
|
|
214
|
+
const border = parseBorder(containerStyles);
|
|
215
|
+
const borderRadius = parseBorderRadius(containerStyles);
|
|
216
|
+
const shadow = parseShadow(containerStyles['box-shadow']);
|
|
217
|
+
|
|
218
|
+
const paddingHorizontal = parseValueWithUnit(containerStyles['padding-left'] || '16px');
|
|
219
|
+
const paddingVertical = parseValueWithUnit(containerStyles['padding-top'] || '12px');
|
|
220
|
+
|
|
221
|
+
const width = widthAttr ? parseFloat(widthAttr) : 100;
|
|
222
|
+
const height = heightAttr ? parseFloat(heightAttr) : 120;
|
|
223
|
+
|
|
224
|
+
// Map align to CF format
|
|
225
|
+
const alignMap = { 'left': 'left', 'center': 'center', 'right': 'right' };
|
|
226
|
+
const marginAlign = alignMap[alignAttr] || 'center';
|
|
227
|
+
|
|
228
|
+
// Parse margin-top with default of 0
|
|
229
|
+
const marginTop = parseValueWithUnit(wrapperStyles['margin-top'] || '0px');
|
|
230
|
+
|
|
231
|
+
const node = {
|
|
232
|
+
type: 'TextArea/V1',
|
|
233
|
+
id,
|
|
234
|
+
version: 0,
|
|
235
|
+
parentId,
|
|
236
|
+
fractionalIndex: generateFractionalIndex(index),
|
|
237
|
+
attrs: {
|
|
238
|
+
'data-skip-shadow-settings': shadow ? 'false' : 'true',
|
|
239
|
+
style: {
|
|
240
|
+
width,
|
|
241
|
+
'margin-top': marginTop.value,
|
|
242
|
+
},
|
|
243
|
+
},
|
|
244
|
+
params: {
|
|
245
|
+
label: placeholder,
|
|
246
|
+
labelType: 'on-border',
|
|
247
|
+
'--style-background-color': background.color || '#ffffff',
|
|
248
|
+
'width--unit': '%',
|
|
249
|
+
'--style-margin-align': marginAlign,
|
|
250
|
+
'margin-top--unit': marginTop.unit,
|
|
251
|
+
height,
|
|
252
|
+
'height--unit': 'px',
|
|
253
|
+
},
|
|
254
|
+
selectors: {
|
|
255
|
+
'.elTextarea': {
|
|
256
|
+
attrs: {
|
|
257
|
+
name: textareaName,
|
|
258
|
+
type: 'custom_type',
|
|
259
|
+
'data-custom-type': textareaName,
|
|
260
|
+
className: isRequired ? 'required1' : 'required0',
|
|
261
|
+
style: {
|
|
262
|
+
height,
|
|
263
|
+
},
|
|
264
|
+
},
|
|
265
|
+
params: {
|
|
266
|
+
'height--unit': 'px',
|
|
267
|
+
'font-size--unit': 'px',
|
|
268
|
+
},
|
|
269
|
+
},
|
|
270
|
+
'.inputHolder, .borderHolder': {
|
|
271
|
+
attrs: {
|
|
272
|
+
style: {
|
|
273
|
+
'padding-top': paddingVertical ? paddingVertical.value : 12,
|
|
274
|
+
'padding-bottom': paddingVertical ? paddingVertical.value : 12,
|
|
275
|
+
},
|
|
276
|
+
},
|
|
277
|
+
params: {
|
|
278
|
+
'--style-padding-horizontal': paddingHorizontal ? paddingHorizontal.value : 16,
|
|
279
|
+
'--style-padding-horizontal--unit': paddingHorizontal ? paddingHorizontal.unit : 'px',
|
|
280
|
+
'padding-top--unit': 'px',
|
|
281
|
+
'padding-bottom--unit': 'px',
|
|
282
|
+
},
|
|
283
|
+
},
|
|
284
|
+
'&.elFormItemWrapper, .inputHolder, .borderHolder': {
|
|
285
|
+
attrs: {
|
|
286
|
+
style: {},
|
|
287
|
+
'data-skip-corners-settings': borderRadius ? 'false' : 'true',
|
|
288
|
+
},
|
|
289
|
+
},
|
|
290
|
+
'.borderHolder': {
|
|
291
|
+
params: {
|
|
292
|
+
'--style-background-color': background.color || '#ffffff',
|
|
293
|
+
},
|
|
294
|
+
},
|
|
295
|
+
},
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
// Apply spacing
|
|
299
|
+
const { attrs: spacingAttrs, params: spacingParams } = spacingToAttrsAndParams(spacing);
|
|
300
|
+
Object.assign(node.attrs.style, spacingAttrs.style);
|
|
301
|
+
Object.assign(node.params, spacingParams);
|
|
302
|
+
|
|
303
|
+
// Apply border
|
|
304
|
+
if (border.width || border.style || border.color) {
|
|
305
|
+
Object.assign(node.selectors['.inputHolder, .borderHolder'].params, borderToParams(border));
|
|
306
|
+
} else {
|
|
307
|
+
node.selectors['.inputHolder, .borderHolder'].params['--style-border-width'] = 1;
|
|
308
|
+
node.selectors['.inputHolder, .borderHolder'].params['--style-border-style'] = 'solid';
|
|
309
|
+
node.selectors['.inputHolder, .borderHolder'].params['--style-border-color'] = 'rgba(0, 0, 0, 0.2)';
|
|
310
|
+
node.selectors['.inputHolder, .borderHolder'].params['--style-border-width--unit'] = 'px';
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// Apply border-radius
|
|
314
|
+
if (borderRadius) {
|
|
315
|
+
node.selectors['&.elFormItemWrapper, .inputHolder, .borderHolder'].attrs.style['border-radius'] = borderRadius.value;
|
|
316
|
+
node.selectors['&.elFormItemWrapper, .inputHolder, .borderHolder'].params = {
|
|
317
|
+
'border-radius--unit': borderRadius.unit,
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Apply shadow
|
|
322
|
+
if (shadow) {
|
|
323
|
+
Object.assign(node.params, shadowToParams(shadow));
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Parse font-size - prefer data attribute, fallback to inline style
|
|
327
|
+
const textareaEl = container ? container.querySelector('textarea') : null;
|
|
328
|
+
const textareaStyles = textareaEl ? parseInlineStyle(textareaEl.getAttribute('style') || '') : {};
|
|
329
|
+
const fontSize = fontSizeAttr
|
|
330
|
+
? parseValueWithUnit(fontSizeAttr)
|
|
331
|
+
: parseValueWithUnit(textareaStyles['font-size'] || '16px');
|
|
332
|
+
if (fontSize) {
|
|
333
|
+
node.selectors['.elTextarea'].attrs.style['font-size'] = fontSize.value;
|
|
334
|
+
node.selectors['.elTextarea'].params['font-size--unit'] = fontSize.unit;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// Parse color - prefer data attribute, fallback to inline style
|
|
338
|
+
const textColor = colorAttr
|
|
339
|
+
? normalizeColor(colorAttr)
|
|
340
|
+
: (textareaStyles.color ? normalizeColor(textareaStyles.color) : null);
|
|
341
|
+
if (textColor) {
|
|
342
|
+
node.selectors['.elTextarea'].attrs.style.color = textColor;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
return node;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Parse SelectBox/V1
|
|
350
|
+
*/
|
|
351
|
+
export function parseSelectBox(element, parentId, index) {
|
|
352
|
+
const id = generateId();
|
|
353
|
+
|
|
354
|
+
const wrapperStyles = parseInlineStyle(element.getAttribute('style') || '');
|
|
355
|
+
const spacing = parseSpacing(wrapperStyles);
|
|
356
|
+
|
|
357
|
+
const selectName = element.getAttribute('data-select-name') || 'option';
|
|
358
|
+
const selectType = element.getAttribute('data-select-type') || 'custom_type';
|
|
359
|
+
const isRequired = element.getAttribute('data-required') === 'true';
|
|
360
|
+
const widthAttr = element.getAttribute('data-width');
|
|
361
|
+
const alignAttr = element.getAttribute('data-align') || 'center';
|
|
362
|
+
const placeholder = element.getAttribute('data-placeholder') || '';
|
|
363
|
+
const fontSizeAttr = element.getAttribute('data-font-size');
|
|
364
|
+
const colorAttr = element.getAttribute('data-color');
|
|
365
|
+
|
|
366
|
+
// Find the container div
|
|
367
|
+
const container = element.querySelector('div');
|
|
368
|
+
const containerStyles = container ? parseInlineStyle(container.getAttribute('style') || '') : {};
|
|
369
|
+
|
|
370
|
+
const background = parseBackground(containerStyles);
|
|
371
|
+
const border = parseBorder(containerStyles);
|
|
372
|
+
const borderRadius = parseBorderRadius(containerStyles);
|
|
373
|
+
const shadow = parseShadow(containerStyles['box-shadow']);
|
|
374
|
+
|
|
375
|
+
const paddingHorizontal = parseValueWithUnit(containerStyles['padding-left'] || '16px');
|
|
376
|
+
const paddingVertical = parseValueWithUnit(containerStyles['padding-top'] || '12px');
|
|
377
|
+
|
|
378
|
+
// Find select element and options
|
|
379
|
+
const select = element.querySelector('select');
|
|
380
|
+
const options = select ? Array.from(select.querySelectorAll('option')) : [];
|
|
381
|
+
|
|
382
|
+
const width = widthAttr ? parseFloat(widthAttr) : 100;
|
|
383
|
+
|
|
384
|
+
// Map align to CF format
|
|
385
|
+
const alignMap = { 'left': 'left', 'center': 'center', 'right': 'right' };
|
|
386
|
+
const marginAlign = alignMap[alignAttr] || 'center';
|
|
387
|
+
|
|
388
|
+
// Parse margin-top with default of 0
|
|
389
|
+
const marginTop = parseValueWithUnit(wrapperStyles['margin-top'] || '0px');
|
|
390
|
+
|
|
391
|
+
// Build children array from options
|
|
392
|
+
const children = options.map((opt, optIndex) => {
|
|
393
|
+
const optionId = generateId();
|
|
394
|
+
const textId = generateId();
|
|
395
|
+
return {
|
|
396
|
+
type: 'option',
|
|
397
|
+
attrs: { value: opt.value || '' },
|
|
398
|
+
id: optionId,
|
|
399
|
+
version: 0,
|
|
400
|
+
parentId: id,
|
|
401
|
+
fractionalIndex: generateFractionalIndex(optIndex),
|
|
402
|
+
children: [
|
|
403
|
+
{
|
|
404
|
+
type: 'text',
|
|
405
|
+
innerText: opt.textContent || '',
|
|
406
|
+
id: textId,
|
|
407
|
+
version: 0,
|
|
408
|
+
parentId: optionId,
|
|
409
|
+
fractionalIndex: 'a0',
|
|
410
|
+
},
|
|
411
|
+
],
|
|
412
|
+
};
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
const node = {
|
|
416
|
+
type: 'SelectBox/V1',
|
|
417
|
+
id,
|
|
418
|
+
version: 0,
|
|
419
|
+
parentId,
|
|
420
|
+
fractionalIndex: generateFractionalIndex(index),
|
|
421
|
+
attrs: {
|
|
422
|
+
style: {
|
|
423
|
+
width,
|
|
424
|
+
'margin-top': marginTop.value,
|
|
425
|
+
},
|
|
426
|
+
},
|
|
427
|
+
params: {
|
|
428
|
+
label: placeholder,
|
|
429
|
+
labelType: 'on-border',
|
|
430
|
+
'width--unit': '%',
|
|
431
|
+
'margin-top--unit': marginTop.unit,
|
|
432
|
+
'--style-margin-align': marginAlign,
|
|
433
|
+
'--style-padding-horizontal': 0,
|
|
434
|
+
'--style-padding-horizontal--unit': 'px',
|
|
435
|
+
'padding-top--unit': 'px',
|
|
436
|
+
'padding-bottom--unit': 'px',
|
|
437
|
+
},
|
|
438
|
+
selectors: {
|
|
439
|
+
'.elSelectWrapper': {
|
|
440
|
+
attrs: { 'data-type': selectType },
|
|
441
|
+
},
|
|
442
|
+
'.elSelect': {
|
|
443
|
+
attrs: {
|
|
444
|
+
'data-skip-corners-settings': borderRadius ? 'false' : 'true',
|
|
445
|
+
'data-skip-shadow-settings': shadow ? 'false' : 'true',
|
|
446
|
+
name: selectType,
|
|
447
|
+
'data-custom-type': selectName,
|
|
448
|
+
className: isRequired ? 'required1' : 'required0',
|
|
449
|
+
style: {
|
|
450
|
+
'padding-top': paddingVertical ? paddingVertical.value : 12,
|
|
451
|
+
'padding-bottom': paddingVertical ? paddingVertical.value : 12,
|
|
452
|
+
},
|
|
453
|
+
},
|
|
454
|
+
params: {
|
|
455
|
+
'--style-background-color': background.color || '#ffffff',
|
|
456
|
+
'--style-padding-horizontal': paddingHorizontal ? paddingHorizontal.value : 16,
|
|
457
|
+
'--style-padding-horizontal--unit': paddingHorizontal ? paddingHorizontal.unit : 'px',
|
|
458
|
+
'padding-top--unit': 'px',
|
|
459
|
+
'padding-bottom--unit': 'px',
|
|
460
|
+
},
|
|
461
|
+
},
|
|
462
|
+
'.elSelect, .elSelectLabel': {
|
|
463
|
+
attrs: {
|
|
464
|
+
style: {},
|
|
465
|
+
},
|
|
466
|
+
params: {
|
|
467
|
+
'font-size--unit': 'px',
|
|
468
|
+
},
|
|
469
|
+
},
|
|
470
|
+
},
|
|
471
|
+
children,
|
|
472
|
+
};
|
|
473
|
+
|
|
474
|
+
// Apply spacing
|
|
475
|
+
const { attrs: spacingAttrs, params: spacingParams } = spacingToAttrsAndParams(spacing);
|
|
476
|
+
Object.assign(node.attrs.style, spacingAttrs.style);
|
|
477
|
+
Object.assign(node.params, spacingParams);
|
|
478
|
+
|
|
479
|
+
// Apply border to .elSelect
|
|
480
|
+
if (border.width || border.style || border.color) {
|
|
481
|
+
Object.assign(node.selectors['.elSelect'].params, borderToParams(border));
|
|
482
|
+
} else {
|
|
483
|
+
node.selectors['.elSelect'].params['--style-border-width'] = 1;
|
|
484
|
+
node.selectors['.elSelect'].params['--style-border-style'] = 'solid';
|
|
485
|
+
node.selectors['.elSelect'].params['--style-border-color'] = 'rgba(0, 0, 0, 0.2)';
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// Apply border-radius to .elSelect
|
|
489
|
+
if (borderRadius) {
|
|
490
|
+
node.selectors['.elSelect'].attrs.style['border-radius'] = borderRadius.value;
|
|
491
|
+
node.selectors['.elSelect'].params['border-radius--unit'] = borderRadius.unit;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// Apply shadow to .elSelect
|
|
495
|
+
if (shadow) {
|
|
496
|
+
Object.assign(node.selectors['.elSelect'].params, shadowToParams(shadow));
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
// Parse font-size - prefer data attribute, fallback to inline style
|
|
500
|
+
const selectEl = container ? container.querySelector('select') : null;
|
|
501
|
+
const selectStyles = selectEl ? parseInlineStyle(selectEl.getAttribute('style') || '') : {};
|
|
502
|
+
const fontSize = fontSizeAttr
|
|
503
|
+
? parseValueWithUnit(fontSizeAttr)
|
|
504
|
+
: parseValueWithUnit(selectStyles['font-size'] || '16px');
|
|
505
|
+
if (fontSize) {
|
|
506
|
+
node.selectors['.elSelect, .elSelectLabel'].attrs.style['font-size'] = fontSize.value;
|
|
507
|
+
node.selectors['.elSelect, .elSelectLabel'].params['font-size--unit'] = fontSize.unit;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// Parse color - prefer data attribute, fallback to inline style
|
|
511
|
+
const textColor = colorAttr
|
|
512
|
+
? normalizeColor(colorAttr)
|
|
513
|
+
: (selectStyles.color ? normalizeColor(selectStyles.color) : null);
|
|
514
|
+
if (textColor) {
|
|
515
|
+
node.selectors['.elSelect, .elSelectLabel'].attrs.style.color = textColor;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
return node;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
/**
|
|
522
|
+
* Parse Checkbox/V1
|
|
523
|
+
*/
|
|
524
|
+
export function parseCheckbox(element, parentId, index) {
|
|
525
|
+
const id = generateId();
|
|
526
|
+
|
|
527
|
+
const wrapperStyles = parseInlineStyle(element.getAttribute('style') || '');
|
|
528
|
+
const spacing = parseSpacing(wrapperStyles);
|
|
529
|
+
|
|
530
|
+
const checkboxName = element.getAttribute('data-name') || 'agree';
|
|
531
|
+
const isChecked = element.getAttribute('data-checked') === 'true';
|
|
532
|
+
const isRequired = element.getAttribute('data-required') === 'true';
|
|
533
|
+
|
|
534
|
+
// Find checkbox label and text
|
|
535
|
+
const label = element.querySelector('label');
|
|
536
|
+
const textSpan = label ? label.querySelector('span:last-child') : null;
|
|
537
|
+
const labelText = textSpan ? textSpan.innerHTML : '';
|
|
538
|
+
|
|
539
|
+
// Find the checkbox box styling
|
|
540
|
+
const checkboxBox = label ? label.querySelector('span:first-of-type') : null;
|
|
541
|
+
const boxStyles = checkboxBox ? parseInlineStyle(checkboxBox.getAttribute('style') || '') : {};
|
|
542
|
+
|
|
543
|
+
const boxSize = parseValueWithUnit(boxStyles.width || '20px');
|
|
544
|
+
const boxBgColor = normalizeColor(boxStyles['background-color'] || '#ffffff');
|
|
545
|
+
const boxBorderMatch = (boxStyles.border || '').match(/(\d+)px\s+\w+\s+(.+)/);
|
|
546
|
+
const boxBorderWidth = boxBorderMatch ? parseInt(boxBorderMatch[1], 10) : 2;
|
|
547
|
+
const boxBorderColor = boxBorderMatch ? normalizeColor(boxBorderMatch[2]) : 'rgb(229, 231, 235)';
|
|
548
|
+
const boxBorderRadius = parseBorderRadius(boxStyles);
|
|
549
|
+
|
|
550
|
+
// Label text styling
|
|
551
|
+
const textStyles = textSpan ? parseInlineStyle(textSpan.getAttribute('style') || '') : {};
|
|
552
|
+
const labelColor = normalizeColor(textStyles.color || '#334155');
|
|
553
|
+
const labelFontSize = parseValueWithUnit(textStyles['font-size'] || '16px');
|
|
554
|
+
|
|
555
|
+
// Gap between checkbox and label
|
|
556
|
+
const labelStyles = label ? parseInlineStyle(label.getAttribute('style') || '') : {};
|
|
557
|
+
const gap = parseValueWithUnit(labelStyles.gap || '12px', 'em');
|
|
558
|
+
|
|
559
|
+
const node = {
|
|
560
|
+
type: 'Checkbox/V1',
|
|
561
|
+
id,
|
|
562
|
+
version: 0,
|
|
563
|
+
parentId,
|
|
564
|
+
fractionalIndex: generateFractionalIndex(index),
|
|
565
|
+
attrs: {
|
|
566
|
+
style: {},
|
|
567
|
+
},
|
|
568
|
+
params: {
|
|
569
|
+
isFormItem: true,
|
|
570
|
+
name: checkboxName,
|
|
571
|
+
checked: isChecked,
|
|
572
|
+
useCheckboxIcon: true,
|
|
573
|
+
required: isRequired,
|
|
574
|
+
},
|
|
575
|
+
selectors: {
|
|
576
|
+
'.elCheckboxLabel': {
|
|
577
|
+
attrs: {
|
|
578
|
+
style: {
|
|
579
|
+
gap: gap ? gap.value : 1,
|
|
580
|
+
},
|
|
581
|
+
},
|
|
582
|
+
params: {
|
|
583
|
+
'gap--unit': gap ? gap.unit : 'em',
|
|
584
|
+
},
|
|
585
|
+
},
|
|
586
|
+
'.elCheckboxLabel .elCheckboxInput ~ .elCheckbox': {
|
|
587
|
+
attrs: {
|
|
588
|
+
style: {
|
|
589
|
+
'font-size': boxSize ? boxSize.value : 20,
|
|
590
|
+
'border-radius': boxBorderRadius ? boxBorderRadius.value : 4,
|
|
591
|
+
'background-color': boxBgColor,
|
|
592
|
+
},
|
|
593
|
+
},
|
|
594
|
+
params: {
|
|
595
|
+
'font-size--unit': boxSize ? boxSize.unit : 'px',
|
|
596
|
+
'--style-border-style': 'solid',
|
|
597
|
+
'--style-border-width': boxBorderWidth,
|
|
598
|
+
'--style-border-width--unit': 'px',
|
|
599
|
+
'--style-border-color': boxBorderColor,
|
|
600
|
+
'border-radius--unit': boxBorderRadius ? boxBorderRadius.unit : 'px',
|
|
601
|
+
},
|
|
602
|
+
},
|
|
603
|
+
'.elCheckboxLabel .elCheckboxInput:checked ~ .elCheckbox': {
|
|
604
|
+
attrs: {
|
|
605
|
+
style: {
|
|
606
|
+
'background-color': 'rgb(59, 130, 246)',
|
|
607
|
+
},
|
|
608
|
+
},
|
|
609
|
+
params: {
|
|
610
|
+
'--style-border-color': 'rgb(59, 130, 246)',
|
|
611
|
+
},
|
|
612
|
+
},
|
|
613
|
+
'.elCheckboxLabel .elCheckboxInput:checked ~ .elCheckboxText': {
|
|
614
|
+
attrs: {
|
|
615
|
+
style: {
|
|
616
|
+
color: labelColor,
|
|
617
|
+
},
|
|
618
|
+
},
|
|
619
|
+
},
|
|
620
|
+
'.elCheckboxLabel .elCheckboxInput ~ .elCheckboxText': {
|
|
621
|
+
attrs: {
|
|
622
|
+
style: {
|
|
623
|
+
color: labelColor,
|
|
624
|
+
},
|
|
625
|
+
},
|
|
626
|
+
},
|
|
627
|
+
'.elCheckboxText': {
|
|
628
|
+
attrs: {
|
|
629
|
+
style: {
|
|
630
|
+
'font-weight': textStyles['font-weight'] || '400',
|
|
631
|
+
'font-size': labelFontSize ? labelFontSize.value : 16,
|
|
632
|
+
},
|
|
633
|
+
},
|
|
634
|
+
params: {
|
|
635
|
+
'font-size--unit': labelFontSize ? labelFontSize.unit : 'px',
|
|
636
|
+
},
|
|
637
|
+
},
|
|
638
|
+
},
|
|
639
|
+
children: [
|
|
640
|
+
{
|
|
641
|
+
type: 'ContentEditableNode',
|
|
642
|
+
slotName: 'label',
|
|
643
|
+
id: '',
|
|
644
|
+
version: 0,
|
|
645
|
+
parentId: '',
|
|
646
|
+
fractionalIndex: 'a0',
|
|
647
|
+
children: parseHtmlToTextNodes(labelText),
|
|
648
|
+
},
|
|
649
|
+
],
|
|
650
|
+
};
|
|
651
|
+
|
|
652
|
+
// Apply spacing
|
|
653
|
+
const { attrs: spacingAttrs, params: spacingParams } = spacingToAttrsAndParams(spacing);
|
|
654
|
+
Object.assign(node.attrs.style, spacingAttrs.style);
|
|
655
|
+
Object.assign(node.params, spacingParams);
|
|
656
|
+
|
|
657
|
+
return node;
|
|
658
|
+
}
|