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.
@@ -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
+ }