ftd/p2/
element.rs

1#[allow(clippy::too_many_arguments)]
2pub fn common_from_properties(
3    unresolved_properties: &ftd::Map<ftd::component::Property>,
4    doc: &ftd::p2::TDoc,
5    condition: &Option<ftd::p2::Boolean>,
6    is_child: bool,
7    events: &[ftd::p2::Event],
8    reference: Option<String>,
9) -> ftd::p1::Result<ftd::Common> {
10    let properties = &ftd::component::resolve_properties(0, unresolved_properties, doc)?;
11    let submit = ftd::p2::utils::string_optional("submit", properties, doc.name, 0)?;
12    let link = ftd::p2::utils::string_optional("link", properties, doc.name, 0)?;
13    if let (Some(_), Some(_)) = (&submit, &link) {
14        return ftd::p2::utils::e2("Cannot have both submit and link together", doc.name, 0);
15    }
16    let gradient_color_str =
17        ftd::p2::utils::string_optional("gradient-colors", properties, doc.name, 0)?;
18
19    let gradient_colors: Vec<ftd::ColorValue> = match gradient_color_str {
20        Some(f) => f
21            .split(',')
22            .flat_map(|x| color_from(Some(x.to_string()), doc.name).ok()?)
23            .collect(),
24        None => vec![],
25    };
26
27    let anchor = ftd::Anchor::from(
28        ftd::p2::utils::string_optional("anchor", properties, doc.name, 0)?,
29        doc.name,
30    )?;
31
32    let (position, inner) = {
33        let mut position = None;
34        let mut inner = match anchor {
35            Some(ref p) => match p {
36                ftd::Anchor::Parent => false,
37                ftd::Anchor::Window => true,
38            },
39            None => false,
40        };
41        let position_inner =
42            match ftd::p2::utils::string_optional("position", properties, doc.name, 0)? {
43                None => ftd::p2::utils::string_optional("align", properties, doc.name, 0)?,
44                Some(v) => Some(v),
45            };
46        if let Some(position_inner) = position_inner {
47            if let Some(p) = position_inner.strip_prefix("inner ") {
48                position = ftd::Position::from(Some(p.to_string()), doc.name)?;
49                inner = true;
50            } else {
51                position = ftd::Position::from(Some(position_inner), doc.name)?;
52            }
53        }
54        (position, inner)
55    };
56
57    let (cond, is_visible) = match condition {
58        Some(c) => {
59            let mut is_visible = true;
60            if !c.eval(0, doc)? {
61                is_visible = false;
62            }
63            if !c.is_arg_constant() {
64                (Some(c.to_condition(0, doc)?), is_visible)
65            } else {
66                (None, is_visible)
67            }
68        }
69        _ => (None, true),
70    };
71
72    Ok(ftd::Common {
73        title: ftd::p2::utils::string_optional("title", properties, doc.name, 0)?,
74        conditional_attribute: Default::default(),
75        condition: cond,
76        is_not_visible: !is_visible,
77        is_dummy: false,
78        events: ftd::p2::Event::get_events(0, events, doc)?,
79        reference,
80        region: ftd::Region::from(
81            ftd::p2::utils::string_optional("region", properties, doc.name, 0)?,
82            doc.name,
83        )?,
84        padding: ftd::p2::utils::int_optional("padding", properties, doc.name, 0)?,
85        padding_vertical: ftd::p2::utils::int_optional(
86            "padding-vertical",
87            properties,
88            doc.name,
89            0,
90        )?,
91        padding_horizontal: ftd::p2::utils::int_optional(
92            "padding-horizontal",
93            properties,
94            doc.name,
95            0,
96        )?,
97        padding_left: ftd::p2::utils::int_optional("padding-left", properties, doc.name, 0)?,
98        padding_right: ftd::p2::utils::int_optional("padding-right", properties, doc.name, 0)?,
99        padding_top: ftd::p2::utils::int_optional("padding-top", properties, doc.name, 0)?,
100        padding_bottom: ftd::p2::utils::int_optional("padding-bottom", properties, doc.name, 0)?,
101        border_top_radius: ftd::p2::utils::int_optional(
102            "border-top-radius",
103            properties,
104            doc.name,
105            0,
106        )?,
107        border_bottom_radius: ftd::p2::utils::int_optional(
108            "border-bottom-radius",
109            properties,
110            doc.name,
111            0,
112        )?,
113        border_left_radius: ftd::p2::utils::int_optional(
114            "border-left-radius",
115            properties,
116            doc.name,
117            0,
118        )?,
119        border_right_radius: ftd::p2::utils::int_optional(
120            "border-right-radius",
121            properties,
122            doc.name,
123            0,
124        )?,
125        width: ftd::Length::from(
126            ftd::p2::utils::string_optional("width", properties, doc.name, 0)?,
127            doc.name,
128        )?,
129        min_width: ftd::Length::from(
130            ftd::p2::utils::string_optional("min-width", properties, doc.name, 0)?,
131            doc.name,
132        )?,
133        max_width: ftd::Length::from(
134            ftd::p2::utils::string_optional("max-width", properties, doc.name, 0)?,
135            doc.name,
136        )?,
137        height: ftd::Length::from(
138            ftd::p2::utils::string_optional("height", properties, doc.name, 0)?,
139            doc.name,
140        )?,
141        min_height: ftd::Length::from(
142            ftd::p2::utils::string_optional("min-height", properties, doc.name, 0)?,
143            doc.name,
144        )?,
145        max_height: ftd::Length::from(
146            ftd::p2::utils::string_optional("max-height", properties, doc.name, 0)?,
147            doc.name,
148        )?,
149        color: ftd::Color::from(
150            ftd::p2::utils::record_optional_with_ref("color", unresolved_properties, doc, 0)?,
151            doc,
152            0,
153        )?,
154        background_color: ftd::Color::from(
155            ftd::p2::utils::record_optional_with_ref(
156                "background-color",
157                unresolved_properties,
158                doc,
159                0,
160            )?,
161            doc,
162            0,
163        )?,
164        border_color: ftd::Color::from(
165            ftd::p2::utils::record_optional_with_ref(
166                "border-color",
167                unresolved_properties,
168                doc,
169                0,
170            )?,
171            doc,
172            0,
173        )?,
174        border_width: ftd::p2::utils::int_with_default("border-width", 0, properties, doc.name, 0)?,
175        border_radius: ftd::p2::utils::int_with_default(
176            "border-radius",
177            0,
178            properties,
179            doc.name,
180            0,
181        )?,
182        data_id: ftd::p2::utils::string_optional("id", properties, doc.name, 0)?.map(|v| {
183            if is_child {
184                v
185            } else {
186                format!("{}#{}", doc.name, v)
187            }
188        }),
189        id: None,
190        overflow_x: ftd::Overflow::from(
191            ftd::p2::utils::string_optional("overflow-x", properties, doc.name, 0)?,
192            doc.name,
193        )?,
194        overflow_y: ftd::Overflow::from(
195            ftd::p2::utils::string_optional("overflow-y", properties, doc.name, 0)?,
196            doc.name,
197        )?,
198        border_top: ftd::p2::utils::int_optional("border-top", properties, doc.name, 0)?,
199        border_left: ftd::p2::utils::int_optional("border-left", properties, doc.name, 0)?,
200        border_right: ftd::p2::utils::int_optional("border-right", properties, doc.name, 0)?,
201        border_bottom: ftd::p2::utils::int_optional("border-bottom", properties, doc.name, 0)?,
202        border_top_color: ftd::Color::from(
203            ftd::p2::utils::record_optional_with_ref(
204                "border-top-color",
205                unresolved_properties,
206                doc,
207                0,
208            )?,
209            doc,
210            0,
211        )?,
212        border_left_color: ftd::Color::from(
213            ftd::p2::utils::record_optional_with_ref(
214                "border-left-color",
215                unresolved_properties,
216                doc,
217                0,
218            )?,
219            doc,
220            0,
221        )?,
222        border_right_color: ftd::Color::from(
223            ftd::p2::utils::record_optional_with_ref(
224                "border-right-color",
225                unresolved_properties,
226                doc,
227                0,
228            )?,
229            doc,
230            0,
231        )?,
232        border_bottom_color: ftd::Color::from(
233            ftd::p2::utils::record_optional_with_ref(
234                "border-bottom-color",
235                unresolved_properties,
236                doc,
237                0,
238            )?,
239            doc,
240            0,
241        )?,
242        margin_top: ftd::p2::utils::int_optional("margin-top", properties, doc.name, 0)?,
243        margin_bottom: ftd::p2::utils::int_optional("margin-bottom", properties, doc.name, 0)?,
244        margin_left: ftd::p2::utils::int_optional("margin-left", properties, doc.name, 0)?,
245        margin_right: ftd::p2::utils::int_optional("margin-right", properties, doc.name, 0)?,
246        link,
247        open_in_new_tab: ftd::p2::utils::bool_with_default(
248            "open-in-new-tab",
249            false,
250            properties,
251            doc.name,
252            0,
253        )?,
254        sticky: ftd::p2::utils::bool_with_default("sticky", false, properties, doc.name, 0)?,
255        top: ftd::p2::utils::int_optional("top", properties, doc.name, 0)?,
256        bottom: ftd::p2::utils::int_optional("bottom", properties, doc.name, 0)?,
257        left: ftd::p2::utils::int_optional("left", properties, doc.name, 0)?,
258        right: ftd::p2::utils::int_optional("right", properties, doc.name, 0)?,
259        cursor: ftd::p2::utils::string_optional("cursor", properties, doc.name, 0)?,
260        submit,
261        shadow_offset_x: ftd::p2::utils::int_optional("shadow-offset-x", properties, doc.name, 0)?,
262        shadow_offset_y: ftd::p2::utils::int_optional("shadow-offset-y", properties, doc.name, 0)?,
263        shadow_size: ftd::p2::utils::int_optional("shadow-size", properties, doc.name, 0)?,
264        shadow_blur: ftd::p2::utils::int_optional("shadow-blur", properties, doc.name, 0)?,
265        shadow_color: ftd::Color::from(
266            ftd::p2::utils::record_optional_with_ref(
267                "shadow-color",
268                unresolved_properties,
269                doc,
270                0,
271            )?,
272            doc,
273            0,
274        )?,
275        gradient_direction: ftd::GradientDirection::from(
276            ftd::p2::utils::string_optional("gradient-direction", properties, doc.name, 0)?,
277            doc.name,
278        )?,
279        anchor,
280        gradient_colors,
281        background_image: {
282            let (src, reference) = ftd::p2::utils::record_optional_with_ref(
283                "background-image",
284                unresolved_properties,
285                doc,
286                0,
287            )?;
288            src.map_or(Ok(None), |r| {
289                ftd::ImageSrc::from(&r, doc, 0, reference).map(Some)
290            })?
291        },
292        background_repeat: ftd::p2::utils::bool_with_default(
293            "background-repeat",
294            false,
295            properties,
296            doc.name,
297            0,
298        )?,
299        background_parallax: ftd::p2::utils::bool_with_default(
300            "background-parallax",
301            false,
302            properties,
303            doc.name,
304            0,
305        )?,
306        scale: ftd::p2::utils::decimal_optional("scale", properties, doc.name, 0)?,
307        scale_x: ftd::p2::utils::decimal_optional("scale-x", properties, doc.name, 0)?,
308        scale_y: ftd::p2::utils::decimal_optional("scale-y", properties, doc.name, 0)?,
309        rotate: ftd::p2::utils::int_optional("rotate", properties, doc.name, 0)?,
310        move_up: ftd::p2::utils::int_optional("move-up", properties, doc.name, 0)?,
311        move_down: ftd::p2::utils::int_optional("move-down", properties, doc.name, 0)?,
312        move_left: ftd::p2::utils::int_optional("move-left", properties, doc.name, 0)?,
313        move_right: ftd::p2::utils::int_optional("move-right", properties, doc.name, 0)?,
314        position,
315        inner,
316        z_index: ftd::p2::utils::int_optional("z-index", properties, doc.name, 0)?,
317        slot: ftd::p2::utils::string_optional("slot", properties, doc.name, 0)?,
318        grid_column: ftd::p2::utils::string_optional("grid-column", properties, doc.name, 0)?,
319        grid_row: ftd::p2::utils::string_optional("grid-row", properties, doc.name, 0)?,
320        white_space: ftd::p2::utils::string_optional("white-space", properties, doc.name, 0)?,
321        border_style: ftd::p2::utils::string_optional("border-style", properties, doc.name, 0)?,
322        text_transform: ftd::p2::utils::string_optional("text-transform", properties, doc.name, 0)?,
323    })
324}
325
326fn common_arguments() -> Vec<(String, ftd::p2::Kind)> {
327    vec![
328        (
329            "padding".to_string(),
330            ftd::p2::Kind::integer().into_optional(),
331        ),
332        (
333            "padding-vertical".to_string(),
334            ftd::p2::Kind::integer().into_optional(),
335        ),
336        (
337            "padding-horizontal".to_string(),
338            ftd::p2::Kind::integer().into_optional(),
339        ),
340        (
341            "padding-left".to_string(),
342            ftd::p2::Kind::integer().into_optional(),
343        ),
344        (
345            "padding-right".to_string(),
346            ftd::p2::Kind::integer().into_optional(),
347        ),
348        (
349            "padding-top".to_string(),
350            ftd::p2::Kind::integer().into_optional(),
351        ),
352        (
353            "padding-bottom".to_string(),
354            ftd::p2::Kind::integer().into_optional(),
355        ),
356        (
357            "border-top-radius".to_string(),
358            ftd::p2::Kind::integer().into_optional(),
359        ),
360        (
361            "border-bottom-radius".to_string(),
362            ftd::p2::Kind::integer().into_optional(),
363        ),
364        (
365            "border-left-radius".to_string(),
366            ftd::p2::Kind::integer().into_optional(),
367        ),
368        (
369            "border-right-radius".to_string(),
370            ftd::p2::Kind::integer().into_optional(),
371        ),
372        ("width".to_string(), ftd::p2::Kind::string().into_optional()),
373        (
374            "min-width".to_string(),
375            ftd::p2::Kind::string().into_optional(),
376        ),
377        (
378            "max-width".to_string(),
379            ftd::p2::Kind::string().into_optional(),
380        ),
381        (
382            "height".to_string(),
383            ftd::p2::Kind::string().into_optional(),
384        ),
385        (
386            "min-height".to_string(),
387            ftd::p2::Kind::string().into_optional(),
388        ),
389        (
390            "max-height".to_string(),
391            ftd::p2::Kind::string().into_optional(),
392        ),
393        (
394            // TODO: remove this after verifying that no existing document is using this
395            "explain".to_string(),
396            ftd::p2::Kind::boolean().into_optional(),
397        ),
398        (
399            "region".to_string(),
400            ftd::p2::Kind::string().into_optional(),
401        ),
402        (
403            "color".to_string(),
404            ftd::p2::Kind::Record {
405                name: "ftd#color".to_string(),
406                default: None,
407                is_reference: false,
408            }
409            .into_optional(),
410        ),
411        (
412            "background-color".to_string(),
413            ftd::p2::Kind::Record {
414                name: "ftd#color".to_string(),
415                default: None,
416                is_reference: false,
417            }
418            .into_optional(),
419        ),
420        (
421            "border-color".to_string(),
422            ftd::p2::Kind::Record {
423                name: "ftd#color".to_string(),
424                default: None,
425                is_reference: false,
426            }
427            .into_optional(),
428        ),
429        (
430            "border-width".to_string(),
431            ftd::p2::Kind::integer().into_optional(),
432        ),
433        (
434            "border-radius".to_string(),
435            ftd::p2::Kind::integer().into_optional(),
436        ),
437        ("id".to_string(), ftd::p2::Kind::string().into_optional()),
438        (
439            "overflow-x".to_string(),
440            ftd::p2::Kind::string().into_optional(),
441        ),
442        (
443            "overflow-y".to_string(),
444            ftd::p2::Kind::string().into_optional(),
445        ),
446        (
447            "border-top".to_string(),
448            ftd::p2::Kind::integer().into_optional(),
449        ),
450        (
451            "border-bottom".to_string(),
452            ftd::p2::Kind::integer().into_optional(),
453        ),
454        (
455            "border-left".to_string(),
456            ftd::p2::Kind::integer().into_optional(),
457        ),
458        (
459            "border-right".to_string(),
460            ftd::p2::Kind::integer().into_optional(),
461        ),
462        (
463            "border-top-color".to_string(),
464            ftd::p2::Kind::record("ftd#color").into_optional(),
465        ),
466        (
467            "border-left-color".to_string(),
468            ftd::p2::Kind::record("ftd#color").into_optional(),
469        ),
470        (
471            "border-right-color".to_string(),
472            ftd::p2::Kind::record("ftd#color").into_optional(),
473        ),
474        (
475            "border-bottom-color".to_string(),
476            ftd::p2::Kind::record("ftd#color").into_optional(),
477        ),
478        (
479            "margin-top".to_string(),
480            ftd::p2::Kind::integer().into_optional(),
481        ),
482        (
483            "margin-bottom".to_string(),
484            ftd::p2::Kind::integer().into_optional(),
485        ),
486        (
487            "margin-left".to_string(),
488            ftd::p2::Kind::integer().into_optional(),
489        ),
490        (
491            "margin-right".to_string(),
492            ftd::p2::Kind::integer().into_optional(),
493        ),
494        ("link".to_string(), ftd::p2::Kind::string().into_optional()),
495        (
496            "submit".to_string(),
497            ftd::p2::Kind::string().into_optional(),
498        ),
499        (
500            "open-in-new-tab".to_string(),
501            ftd::p2::Kind::boolean().into_optional(),
502        ),
503        (
504            "sticky".to_string(),
505            ftd::p2::Kind::boolean().into_optional(),
506        ),
507        ("top".to_string(), ftd::p2::Kind::integer().into_optional()),
508        (
509            "bottom".to_string(),
510            ftd::p2::Kind::integer().into_optional(),
511        ),
512        ("left".to_string(), ftd::p2::Kind::integer().into_optional()),
513        (
514            "right".to_string(),
515            ftd::p2::Kind::integer().into_optional(),
516        ),
517        (
518            "cursor".to_string(),
519            ftd::p2::Kind::string().into_optional(),
520        ),
521        (
522            "anchor".to_string(),
523            ftd::p2::Kind::string().into_optional(),
524        ),
525        (
526            "gradient-direction".to_string(),
527            ftd::p2::Kind::string().into_optional(),
528        ),
529        (
530            "gradient-colors".to_string(),
531            ftd::p2::Kind::string().into_optional(),
532        ),
533        (
534            "shadow-offset-x".to_string(),
535            ftd::p2::Kind::integer().into_optional(),
536        ),
537        (
538            "shadow-offset-y".to_string(),
539            ftd::p2::Kind::integer().into_optional(),
540        ),
541        (
542            "shadow-blur".to_string(),
543            ftd::p2::Kind::integer().into_optional(),
544        ),
545        (
546            "shadow-size".to_string(),
547            ftd::p2::Kind::integer().into_optional(),
548        ),
549        (
550            "shadow-color".to_string(),
551            ftd::p2::Kind::record("ftd#color").into_optional(),
552        ),
553        (
554            "background-image".to_string(),
555            ftd::p2::Kind::record("ftd#image-src").into_optional(),
556        ),
557        (
558            "background-repeat".to_string(),
559            ftd::p2::Kind::boolean().into_optional(),
560        ),
561        (
562            "background-parallax".to_string(),
563            ftd::p2::Kind::boolean().into_optional(),
564        ),
565        (
566            "scale".to_string(),
567            ftd::p2::Kind::decimal().into_optional(),
568        ),
569        (
570            "scale-x".to_string(),
571            ftd::p2::Kind::decimal().into_optional(),
572        ),
573        (
574            "scale-y".to_string(),
575            ftd::p2::Kind::decimal().into_optional(),
576        ),
577        (
578            "rotate".to_string(),
579            ftd::p2::Kind::integer().into_optional(),
580        ),
581        (
582            "move-up".to_string(),
583            ftd::p2::Kind::integer().into_optional(),
584        ),
585        (
586            "move-down".to_string(),
587            ftd::p2::Kind::integer().into_optional(),
588        ),
589        (
590            "move-left".to_string(),
591            ftd::p2::Kind::integer().into_optional(),
592        ),
593        (
594            "move-right".to_string(),
595            ftd::p2::Kind::integer().into_optional(),
596        ),
597        (
598            "position".to_string(),
599            ftd::p2::Kind::string().into_optional(),
600        ),
601        (
602            "z-index".to_string(),
603            ftd::p2::Kind::integer().into_optional(),
604        ),
605        ("slot".to_string(), ftd::p2::Kind::string().into_optional()),
606        (
607            "white-space".to_string(),
608            ftd::p2::Kind::string().into_optional(),
609        ),
610        (
611            "border-style".to_string(),
612            ftd::p2::Kind::string().into_optional(),
613        ),
614        (
615            "text-transform".to_string(),
616            ftd::p2::Kind::string().into_optional(),
617        ),
618        /*(
619            "grid-column".to_string(),
620            ftd::p2::Kind::string().into_optional(),
621        ),
622        (
623            "grid-row".to_string(),
624            ftd::p2::Kind::string().into_optional(),
625        ),*/
626    ]
627}
628
629pub fn null() -> ftd::Component {
630    ftd::Component {
631        kernel: true,
632        full_name: "ftd#null".to_string(),
633        root: "ftd.kernel".to_string(),
634        ..Default::default()
635    }
636}
637
638pub fn container_from_properties(
639    properties: &ftd::Map<ftd::Value>,
640    doc: &ftd::p2::TDoc,
641) -> ftd::p1::Result<ftd::Container> {
642    Ok(ftd::Container {
643        children: Default::default(),
644        external_children: Default::default(),
645        open: ftd::p2::utils::bool_optional("open", properties, doc.name, 0)?,
646        append_at: ftd::p2::utils::string_optional("append-at", properties, doc.name, 0)?,
647        wrap: ftd::p2::utils::bool_with_default("wrap", false, properties, doc.name, 0)?,
648    })
649}
650
651fn container_arguments() -> Vec<(String, ftd::p2::Kind)> {
652    vec![
653        ("open".to_string(), ftd::p2::Kind::boolean().into_optional()),
654        (
655            "append-at".to_string(),
656            ftd::p2::Kind::string().into_optional(),
657        ),
658        ("align".to_string(), ftd::p2::Kind::string().into_optional()),
659        ("wrap".to_string(), ftd::p2::Kind::boolean().into_optional()),
660    ]
661}
662
663pub fn image_function() -> ftd::Component {
664    ftd::Component {
665        kernel: true,
666        full_name: "ftd#image".to_string(),
667        root: "ftd.kernel".to_string(),
668        arguments: [
669            vec![
670                ("src".to_string(), ftd::p2::Kind::record("ftd#image-src")),
671                (
672                    "description".to_string(),
673                    ftd::p2::Kind::string().into_optional(),
674                ),
675                ("title".to_string(), ftd::p2::Kind::string().into_optional()),
676                ("align".to_string(), ftd::p2::Kind::string().into_optional()),
677                ("crop".to_string(), ftd::p2::Kind::boolean().into_optional()),
678                (
679                    "loading".to_string(),
680                    ftd::p2::Kind::string().into_optional(),
681                ),
682            ],
683            common_arguments(),
684        ]
685        .concat()
686        .into_iter()
687        .collect(),
688        locals: Default::default(),
689        properties: Default::default(),
690        instructions: Default::default(),
691        invocations: Default::default(),
692        condition: None,
693        events: vec![],
694        line_number: 0,
695    }
696}
697
698pub fn image_from_properties(
699    unresolved_properties: &ftd::Map<ftd::component::Property>,
700    doc: &ftd::p2::TDoc,
701    condition: &Option<ftd::p2::Boolean>,
702    is_child: bool,
703    events: &[ftd::p2::Event],
704) -> ftd::p1::Result<ftd::Image> {
705    let (src, reference) =
706        ftd::p2::utils::record_and_ref(0, "src", unresolved_properties, doc, condition)?;
707    let src_record = ftd::ImageSrc::from(&src, doc, 0, reference.clone())?;
708    let properties = &ftd::component::resolve_properties(0, unresolved_properties, doc)?;
709    Ok(ftd::Image {
710        src: src_record,
711        description: ftd::p2::utils::string_optional("description", properties, doc.name, 0)?,
712        common: common_from_properties(
713            unresolved_properties,
714            doc,
715            condition,
716            is_child,
717            events,
718            reference,
719        )?,
720        loading: ftd::Loading::from(
721            ftd::p2::utils::string_with_default("loading", "lazy", properties, doc.name, 0)?
722                .as_str(),
723            doc.name,
724        )?,
725        crop: ftd::p2::utils::bool_with_default("crop", false, properties, doc.name, 0)?,
726    })
727}
728
729pub fn row_function() -> ftd::Component {
730    ftd::Component {
731        kernel: true,
732        full_name: "ftd#row".to_string(),
733        root: "ftd.kernel".to_string(),
734        arguments: [
735            container_arguments(),
736            common_arguments(),
737            vec![(
738                "spacing".to_string(),
739                ftd::p2::Kind::string().into_optional(),
740            )],
741        ]
742        .concat()
743        .into_iter()
744        .collect(),
745        locals: Default::default(),
746        properties: Default::default(),
747        instructions: Default::default(),
748        invocations: Default::default(),
749        condition: None,
750        events: vec![],
751        line_number: 0,
752    }
753}
754
755pub fn row_from_properties(
756    unresolved_properties: &ftd::Map<ftd::component::Property>,
757    doc: &ftd::p2::TDoc,
758    condition: &Option<ftd::p2::Boolean>,
759    is_child: bool,
760    events: &[ftd::p2::Event],
761) -> ftd::p1::Result<ftd::Row> {
762    let properties = &ftd::component::resolve_properties(0, unresolved_properties, doc)?;
763    Ok(ftd::Row {
764        common: common_from_properties(
765            unresolved_properties,
766            doc,
767            condition,
768            is_child,
769            events,
770            None,
771        )?,
772        container: container_from_properties(properties, doc)?,
773        spacing: ftd::Spacing::from(ftd::p2::utils::string_optional(
774            "spacing", properties, doc.name, 0,
775        )?)?,
776    })
777}
778
779pub fn column_function() -> ftd::Component {
780    ftd::Component {
781        line_number: 0,
782        kernel: true,
783        full_name: "ftd#column".to_string(),
784        root: "ftd.kernel".to_string(),
785        arguments: [
786            container_arguments(),
787            common_arguments(),
788            vec![(
789                "spacing".to_string(),
790                ftd::p2::Kind::string().into_optional(),
791            )],
792        ]
793        .concat()
794        .into_iter()
795        .collect(),
796        locals: Default::default(),
797        properties: Default::default(),
798        instructions: Default::default(),
799        invocations: Default::default(),
800        condition: None,
801        events: vec![],
802    }
803}
804
805pub fn column_from_properties(
806    unresolved_properties: &ftd::Map<ftd::component::Property>,
807    doc: &ftd::p2::TDoc,
808    condition: &Option<ftd::p2::Boolean>,
809    is_child: bool,
810    events: &[ftd::p2::Event],
811) -> ftd::p1::Result<ftd::Column> {
812    let properties = &ftd::component::resolve_properties(0, unresolved_properties, doc)?;
813    Ok(ftd::Column {
814        common: common_from_properties(
815            unresolved_properties,
816            doc,
817            condition,
818            is_child,
819            events,
820            None,
821        )?,
822        container: container_from_properties(properties, doc)?,
823        spacing: ftd::Spacing::from(ftd::p2::utils::string_optional(
824            "spacing", properties, doc.name, 0,
825        )?)?,
826    })
827}
828
829#[allow(dead_code)]
830#[allow(unused_variables)]
831pub fn text_render(
832    tf: &ftd::TextFormat,
833    text: String,
834    source: ftd::TextSource,
835    theme: String,
836    doc_id: &str,
837) -> ftd::p1::Result<ftd::Rendered> {
838    Ok(match (source, tf) {
839        (ftd::TextSource::Body, ftd::TextFormat::Markdown) => ftd::rendered::markup(text.as_str()),
840        (_, ftd::TextFormat::Markdown) => ftd::rendered::markup_line(text.as_str()),
841        (_, ftd::TextFormat::Code { lang }) => {
842            ftd::rendered::code_with_theme(text.as_str(), lang.as_str(), theme.as_str(), doc_id)?
843        }
844        (_, ftd::TextFormat::Text) => ftd::Rendered {
845            original: text.clone(),
846            rendered: text,
847        },
848    })
849}
850
851pub fn iframe_function() -> ftd::Component {
852    ftd::Component {
853        line_number: 0,
854        kernel: true,
855        root: "ftd.kernel".to_string(),
856        full_name: "ftd#iframe".to_string(),
857        arguments: [
858            vec![
859                ("src".to_string(), ftd::p2::Kind::string().into_optional()),
860                (
861                    "youtube".to_string(),
862                    ftd::p2::Kind::string().into_optional(),
863                ),
864                (
865                    "loading".to_string(),
866                    ftd::p2::Kind::string().into_optional(),
867                ),
868            ],
869            common_arguments(),
870        ]
871        .concat()
872        .into_iter()
873        .collect(),
874        locals: Default::default(),
875        properties: Default::default(),
876        instructions: Default::default(),
877        invocations: Default::default(),
878        condition: None,
879        events: vec![],
880    }
881}
882
883pub fn iframe_from_properties(
884    unresolved_properties: &ftd::Map<ftd::component::Property>,
885    doc: &ftd::p2::TDoc,
886    condition: &Option<ftd::p2::Boolean>,
887    is_child: bool,
888    events: &[ftd::p2::Event],
889) -> ftd::p1::Result<ftd::IFrame> {
890    let properties = &ftd::component::resolve_properties(0, unresolved_properties, doc)?;
891    let src = match (
892        ftd::p2::utils::string_optional("src", properties, doc.name, 0)?,
893        ftd::p2::utils::string_optional("youtube", properties, doc.name, 0)?
894            .and_then(|id| ftd::youtube_id::from_raw(id.as_str())),
895    ) {
896        (Some(src), None) => src,
897        (None, Some(id)) => id,
898        (Some(_), Some(_)) => {
899            return ftd::p2::utils::e2("both src and youtube id provided", doc.name, 0)
900        }
901        (None, None) => return ftd::p2::utils::e2("src or youtube id is required", doc.name, 0),
902    };
903
904    Ok(ftd::IFrame {
905        src,
906        loading: ftd::Loading::from(
907            ftd::p2::utils::string_with_default("loading", "lazy", properties, doc.name, 0)?
908                .as_str(),
909            doc.name,
910        )?,
911        common: common_from_properties(
912            unresolved_properties,
913            doc,
914            condition,
915            is_child,
916            events,
917            None,
918        )?,
919    })
920}
921
922pub fn text_block_from_properties(
923    unresolved_properties: &ftd::Map<ftd::component::Property>,
924    doc: &ftd::p2::TDoc,
925    condition: &Option<ftd::p2::Boolean>,
926    is_child: bool,
927    events: &[ftd::p2::Event],
928) -> ftd::p1::Result<ftd::TextBlock> {
929    let (text, source, reference) = ftd::p2::utils::string_and_source_and_ref(
930        0,
931        "text",
932        unresolved_properties,
933        doc,
934        condition,
935    )?;
936    let properties = &ftd::component::resolve_properties(0, unresolved_properties, doc)?;
937    let font_str = ftd::p2::utils::string_optional("role", properties, doc.name, 0)?;
938
939    let font: Vec<ftd::NamedFont> = match font_str {
940        Some(f) => f
941            .split(',')
942            .flat_map(|x| ftd::NamedFont::from(Some(x.to_string())))
943            .collect(),
944        None => vec![],
945    };
946    Ok(ftd::TextBlock {
947        line: source != ftd::TextSource::Body,
948        text: if source == ftd::TextSource::Body {
949            ftd::rendered::markup(text.as_str())
950        } else {
951            ftd::rendered::markup_line(text.as_str())
952        },
953        common: common_from_properties(
954            unresolved_properties,
955            doc,
956            condition,
957            is_child,
958            events,
959            reference,
960        )?,
961        text_align: ftd::TextAlign::from(
962            ftd::p2::utils::string_optional("text-align", properties, doc.name, 0)?,
963            doc.name,
964        )?,
965        style: ftd::Style::from(
966            ftd::p2::utils::string_optional("style", properties, doc.name, 0)?,
967            doc.name,
968        )?,
969        size: ftd::p2::utils::int_optional("size", properties, doc.name, 0)?,
970        font,
971        line_height: ftd::p2::utils::int_optional("line-height", properties, doc.name, 0)?,
972        line_clamp: ftd::p2::utils::int_optional("line-clamp", properties, doc.name, 0)?,
973        text_indent: ftd::Length::from(
974            ftd::p2::utils::string_optional("text-indent", properties, doc.name, 0)?,
975            doc.name,
976        )?,
977    })
978}
979
980pub fn code_from_properties(
981    unresolved_properties: &ftd::Map<ftd::component::Property>,
982    doc: &ftd::p2::TDoc,
983    condition: &Option<ftd::p2::Boolean>,
984    is_child: bool,
985    events: &[ftd::p2::Event],
986) -> ftd::p1::Result<ftd::Code> {
987    let (text, _, reference) = ftd::p2::utils::string_and_source_and_ref(
988        0,
989        "text",
990        unresolved_properties,
991        doc,
992        condition,
993    )?;
994    let properties = &ftd::component::resolve_properties(0, unresolved_properties, doc)?;
995    let font_str = ftd::p2::utils::record_optional("role", properties, doc.name, 0)?;
996    let mut font_reference = None;
997    if font_str.is_some() {
998        font_reference =
999            ftd::p2::utils::record_and_ref(0, "role", unresolved_properties, doc, condition)?.1;
1000    }
1001    let font = font_str.map_or(Ok(None), |v| {
1002        ftd::Type::from(&v, doc, 0, font_reference).map(Some)
1003    })?;
1004
1005    Ok(ftd::Code {
1006        text: ftd::rendered::code_with_theme(
1007            text.as_str(),
1008            ftd::p2::utils::string_optional("lang", properties, doc.name, 0)?
1009                .unwrap_or_else(|| "txt".to_string())
1010                .as_str(),
1011            ftd::p2::utils::string_with_default(
1012                "theme",
1013                ftd::code::DEFAULT_THEME,
1014                properties,
1015                doc.name,
1016                0,
1017            )?
1018            .as_str(),
1019            doc.name,
1020        )?,
1021        common: common_from_properties(
1022            unresolved_properties,
1023            doc,
1024            condition,
1025            is_child,
1026            events,
1027            reference,
1028        )?,
1029        text_align: ftd::TextAlign::from(
1030            ftd::p2::utils::string_optional("text-align", properties, doc.name, 0)?,
1031            doc.name,
1032        )?,
1033        style: ftd::Style::from(
1034            ftd::p2::utils::string_optional("style", properties, doc.name, 0)?,
1035            doc.name,
1036        )?,
1037        font,
1038        line_clamp: ftd::p2::utils::int_optional("line-clamp", properties, doc.name, 0)?,
1039        text_indent: ftd::Length::from(
1040            ftd::p2::utils::string_optional("text-indent", properties, doc.name, 0)?,
1041            doc.name,
1042        )?,
1043    })
1044}
1045
1046pub fn integer_from_properties(
1047    unresolved_properties: &ftd::Map<ftd::component::Property>,
1048    doc: &ftd::p2::TDoc,
1049    condition: &Option<ftd::p2::Boolean>,
1050    is_child: bool,
1051    events: &[ftd::p2::Event],
1052) -> ftd::p1::Result<ftd::Text> {
1053    let reference =
1054        ftd::p2::utils::integer_and_ref(0, "value", unresolved_properties, doc, condition)?.1;
1055    let properties = &ftd::component::resolve_properties(0, unresolved_properties, doc)?;
1056    let num = format_num::NumberFormat::new();
1057    let text = match ftd::p2::utils::string_optional("format", properties, doc.name, 0)? {
1058        Some(f) => num.format(
1059            f.as_str(),
1060            ftd::p2::utils::int("value", properties, doc.name, 0)? as f64,
1061        ),
1062        None => ftd::p2::utils::int("value", properties, doc.name, 0)?.to_string(),
1063    };
1064
1065    let font_str = ftd::p2::utils::record_optional("role", properties, doc.name, 0)?;
1066    let mut font_reference = None;
1067    if font_str.is_some() {
1068        font_reference =
1069            ftd::p2::utils::record_and_ref(0, "role", unresolved_properties, doc, condition)?.1;
1070    }
1071    let font = font_str.map_or(Ok(None), |v| {
1072        ftd::Type::from(&v, doc, 0, font_reference).map(Some)
1073    })?;
1074
1075    Ok(ftd::Text {
1076        text: ftd::rendered::markup_line(text.as_str()),
1077        line: false,
1078        common: common_from_properties(
1079            unresolved_properties,
1080            doc,
1081            condition,
1082            is_child,
1083            events,
1084            reference,
1085        )?,
1086        text_align: ftd::TextAlign::from(
1087            ftd::p2::utils::string_optional("text-align", properties, doc.name, 0)?,
1088            doc.name,
1089        )?,
1090        style: ftd::Style::from(
1091            ftd::p2::utils::string_optional("style", properties, doc.name, 0)?,
1092            doc.name,
1093        )?,
1094        font,
1095        line_clamp: ftd::p2::utils::int_optional("line-clamp", properties, doc.name, 0)?,
1096        text_indent: ftd::Length::from(
1097            ftd::p2::utils::string_optional("text-indent", properties, doc.name, 0)?,
1098            doc.name,
1099        )?,
1100    })
1101}
1102
1103pub fn decimal_from_properties(
1104    unresolved_properties: &ftd::Map<ftd::component::Property>,
1105    doc: &ftd::p2::TDoc,
1106    condition: &Option<ftd::p2::Boolean>,
1107    is_child: bool,
1108    events: &[ftd::p2::Event],
1109) -> ftd::p1::Result<ftd::Text> {
1110    let reference =
1111        ftd::p2::utils::decimal_and_ref(0, "value", unresolved_properties, doc, condition)?.1;
1112    let properties = &ftd::component::resolve_properties(0, unresolved_properties, doc)?;
1113    let num = format_num::NumberFormat::new();
1114    let text = match ftd::p2::utils::string_optional("format", properties, doc.name, 0)? {
1115        Some(f) => num.format(
1116            f.as_str(),
1117            ftd::p2::utils::decimal("value", properties, doc.name, 0)?,
1118        ),
1119        None => ftd::p2::utils::decimal("value", properties, doc.name, 0)?.to_string(),
1120    };
1121
1122    let font_str = ftd::p2::utils::record_optional("role", properties, doc.name, 0)?;
1123    let mut font_reference = None;
1124    if font_str.is_some() {
1125        font_reference =
1126            ftd::p2::utils::record_and_ref(0, "role", unresolved_properties, doc, condition)?.1;
1127    }
1128    let font = font_str.map_or(Ok(None), |v| {
1129        ftd::Type::from(&v, doc, 0, font_reference).map(Some)
1130    })?;
1131    Ok(ftd::Text {
1132        text: ftd::rendered::markup_line(text.as_str()),
1133        line: false,
1134        common: common_from_properties(
1135            unresolved_properties,
1136            doc,
1137            condition,
1138            is_child,
1139            events,
1140            reference,
1141        )?,
1142        text_align: ftd::TextAlign::from(
1143            ftd::p2::utils::string_optional("text-align", properties, doc.name, 0)?,
1144            doc.name,
1145        )?,
1146        style: ftd::Style::from(
1147            ftd::p2::utils::string_optional("style", properties, doc.name, 0)?,
1148            doc.name,
1149        )?,
1150        font,
1151        line_clamp: ftd::p2::utils::int_optional("line-clamp", properties, doc.name, 0)?,
1152        text_indent: ftd::Length::from(
1153            ftd::p2::utils::string_optional("text-indent", properties, doc.name, 0)?,
1154            doc.name,
1155        )?,
1156    })
1157}
1158
1159pub fn color_from(l: Option<String>, doc_id: &str) -> ftd::p1::Result<Option<ftd::ColorValue>> {
1160    use std::str::FromStr;
1161
1162    let v = match l {
1163        Some(v) => v,
1164        None => return Ok(None),
1165    };
1166
1167    let v = v.trim().to_string();
1168
1169    // Remove all whitespace, not compliant, but should just be more accepting.
1170    let mut string = v.replace(' ', "");
1171    string.make_ascii_lowercase();
1172    if v.starts_with('#') && v.len() == 9 {
1173        let (_, value_string) = string.split_at(1);
1174
1175        let iv = u64::from_str_radix(value_string, 16).map_err(|e| ftd::p1::Error::ParseError {
1176            message: e.to_string(),
1177            doc_id: doc_id.to_string(),
1178            line_number: 0,
1179        })?;
1180
1181        // (7thSigil) unlike original js code, NaN is impossible
1182        if iv > 0xffffffff {
1183            return ftd::p2::utils::e2(format!("{} is not a valid color", v), doc_id, 0);
1184        }
1185
1186        //Code for accepting 6-digit hexa-color code
1187        Ok(Some(ftd::ColorValue {
1188            r: ((iv & 0xff000000) >> 24) as u8,
1189            g: ((iv & 0xff0000) >> 16) as u8,
1190            b: ((iv & 0xff00) >> 8) as u8,
1191            alpha: round_1p((iv & 0xff) as f32 / 255_f32) as f32,
1192        }))
1193    } else {
1194        match css_color_parser::Color::from_str(v.as_str()) {
1195            Ok(v) => Ok(Some(ftd::ColorValue {
1196                r: v.r,
1197                g: v.g,
1198                b: v.b,
1199                alpha: v.a,
1200            })),
1201            Err(e) => ftd::p2::utils::e2(format!("{} is not a valid color: {:?}", v, e), doc_id, 0),
1202        }
1203    }
1204}
1205fn round_1p(n: f32) -> f32 {
1206    // 1234.56
1207    let temp = (n * 10_f32) as u32;
1208    let last = (temp % 10) as f32;
1209    let front = n as u32;
1210
1211    front as f32 + last / 10_f32
1212}
1213
1214pub fn boolean_from_properties(
1215    unresolved_properties: &ftd::Map<ftd::component::Property>,
1216    doc: &ftd::p2::TDoc,
1217    condition: &Option<ftd::p2::Boolean>,
1218    is_child: bool,
1219    events: &[ftd::p2::Event],
1220) -> ftd::p1::Result<ftd::Text> {
1221    let reference =
1222        ftd::p2::utils::boolean_and_ref(0, "value", unresolved_properties, doc, condition)?.1;
1223    let properties = &ftd::component::resolve_properties(0, unresolved_properties, doc)?;
1224    let value = ftd::p2::utils::bool_("value", properties, doc.name, 0)?;
1225    let text = if value {
1226        ftd::p2::utils::string_with_default("true", "true", properties, doc.name, 0)?
1227    } else {
1228        ftd::p2::utils::string_with_default("false", "false", properties, doc.name, 0)?
1229    };
1230
1231    let font_str = ftd::p2::utils::record_optional("role", properties, doc.name, 0)?;
1232    let mut font_reference = None;
1233    if font_str.is_some() {
1234        font_reference =
1235            ftd::p2::utils::record_and_ref(0, "role", unresolved_properties, doc, condition)?.1;
1236    }
1237    let font = font_str.map_or(Ok(None), |v| {
1238        ftd::Type::from(&v, doc, 0, font_reference).map(Some)
1239    })?;
1240
1241    Ok(ftd::Text {
1242        text: ftd::rendered::markup_line(text.as_str()),
1243        line: false,
1244        common: common_from_properties(
1245            unresolved_properties,
1246            doc,
1247            condition,
1248            is_child,
1249            events,
1250            reference,
1251        )?,
1252        text_align: ftd::TextAlign::from(
1253            ftd::p2::utils::string_optional("text-align", properties, doc.name, 0)?,
1254            doc.name,
1255        )?,
1256        style: ftd::Style::from(
1257            ftd::p2::utils::string_optional("style", properties, doc.name, 0)?,
1258            doc.name,
1259        )?,
1260        font,
1261        line_clamp: ftd::p2::utils::int_optional("line-clamp", properties, doc.name, 0)?,
1262        text_indent: ftd::Length::from(
1263            ftd::p2::utils::string_optional("text-indent", properties, doc.name, 0)?,
1264            doc.name,
1265        )?,
1266    })
1267}
1268
1269pub fn text_function() -> ftd::Component {
1270    ftd::Component {
1271        line_number: 0,
1272        kernel: true,
1273        root: "ftd.kernel".to_string(),
1274        full_name: "ftd#text-block".to_string(),
1275        arguments: [
1276            vec![
1277                ("text".to_string(), ftd::p2::Kind::caption_or_body()),
1278                ("align".to_string(), ftd::p2::Kind::string().into_optional()),
1279                ("style".to_string(), ftd::p2::Kind::string().into_optional()),
1280                (
1281                    "role".to_string(),
1282                    ftd::p2::Kind::record("ftd#type").into_optional(),
1283                ),
1284                (
1285                    "line-clamp".to_string(),
1286                    ftd::p2::Kind::integer().into_optional(),
1287                ),
1288                (
1289                    "text-indent".to_string(),
1290                    ftd::p2::Kind::integer().into_optional(),
1291                ),
1292                (
1293                    "text-align".to_string(),
1294                    ftd::p2::Kind::string().into_optional(),
1295                ),
1296            ],
1297            common_arguments(),
1298        ]
1299        .concat()
1300        .into_iter()
1301        .collect(),
1302        locals: Default::default(),
1303        properties: Default::default(),
1304        instructions: Default::default(),
1305        invocations: Default::default(),
1306        condition: None,
1307        events: vec![],
1308    }
1309}
1310
1311pub fn code_function() -> ftd::Component {
1312    ftd::Component {
1313        line_number: 0,
1314        kernel: true,
1315        root: "ftd.kernel".to_string(),
1316        full_name: "ftd#code".to_string(),
1317        arguments: [
1318            vec![
1319                ("text".to_string(), ftd::p2::Kind::caption_or_body()),
1320                ("align".to_string(), ftd::p2::Kind::string().into_optional()),
1321                ("style".to_string(), ftd::p2::Kind::string().into_optional()),
1322                ("lang".to_string(), ftd::p2::Kind::string().into_optional()),
1323                ("theme".to_string(), ftd::p2::Kind::string().into_optional()),
1324                (
1325                    "role".to_string(),
1326                    ftd::p2::Kind::record("ftd#type").into_optional(),
1327                ),
1328                (
1329                    "line-clamp".to_string(),
1330                    ftd::p2::Kind::integer().into_optional(),
1331                ),
1332                (
1333                    "text-indent".to_string(),
1334                    ftd::p2::Kind::string().into_optional(),
1335                ),
1336                (
1337                    "text-align".to_string(),
1338                    ftd::p2::Kind::string().into_optional(),
1339                ),
1340            ],
1341            common_arguments(),
1342        ]
1343        .concat()
1344        .into_iter()
1345        .collect(),
1346        locals: Default::default(),
1347        properties: Default::default(),
1348        instructions: Default::default(),
1349        invocations: Default::default(),
1350        condition: None,
1351        events: vec![],
1352    }
1353}
1354
1355pub fn integer_function() -> ftd::Component {
1356    ftd::Component {
1357        line_number: 0,
1358        kernel: true,
1359        root: "ftd.kernel".to_string(),
1360        full_name: "ftd#integer".to_string(),
1361        arguments: [
1362            vec![
1363                ("value".to_string(), ftd::p2::Kind::integer()),
1364                ("align".to_string(), ftd::p2::Kind::string().into_optional()),
1365                ("style".to_string(), ftd::p2::Kind::string().into_optional()),
1366                (
1367                    "format".to_string(),
1368                    ftd::p2::Kind::string().into_optional(),
1369                ),
1370                (
1371                    "role".to_string(),
1372                    ftd::p2::Kind::record("ftd#type").into_optional(),
1373                ),
1374                (
1375                    "text-align".to_string(),
1376                    ftd::p2::Kind::string().into_optional(),
1377                ),
1378            ],
1379            common_arguments(),
1380        ]
1381        .concat()
1382        .into_iter()
1383        .collect(),
1384        locals: Default::default(),
1385        properties: Default::default(),
1386        instructions: Default::default(),
1387        invocations: Default::default(),
1388        condition: None,
1389        events: vec![],
1390    }
1391}
1392
1393pub fn decimal_function() -> ftd::Component {
1394    ftd::Component {
1395        line_number: 0,
1396        kernel: true,
1397        root: "ftd.kernel".to_string(),
1398        full_name: "ftd#decimal".to_string(),
1399        arguments: [
1400            vec![
1401                ("value".to_string(), ftd::p2::Kind::decimal()),
1402                ("align".to_string(), ftd::p2::Kind::string().into_optional()),
1403                ("style".to_string(), ftd::p2::Kind::string().into_optional()),
1404                (
1405                    "format".to_string(),
1406                    ftd::p2::Kind::string().into_optional(),
1407                ),
1408                (
1409                    "role".to_string(),
1410                    ftd::p2::Kind::record("ftd#type").into_optional(),
1411                ),
1412                (
1413                    "text-align".to_string(),
1414                    ftd::p2::Kind::string().into_optional(),
1415                ),
1416            ],
1417            common_arguments(),
1418        ]
1419        .concat()
1420        .into_iter()
1421        .collect(),
1422        locals: Default::default(),
1423        properties: Default::default(),
1424        instructions: Default::default(),
1425        invocations: Default::default(),
1426        condition: None,
1427        events: vec![],
1428    }
1429}
1430
1431pub fn scene_function() -> ftd::Component {
1432    let arguments = {
1433        let mut arguments: ftd::Map<ftd::p2::Kind> = [
1434            container_arguments(),
1435            common_arguments(),
1436            vec![(
1437                "spacing".to_string(),
1438                ftd::p2::Kind::string().into_optional(),
1439            )],
1440        ]
1441        .concat()
1442        .into_iter()
1443        .collect();
1444        arguments.remove("spacing");
1445        arguments.remove("wrap");
1446        arguments
1447    };
1448
1449    ftd::Component {
1450        line_number: 0,
1451        kernel: true,
1452        root: "ftd.kernel".to_string(),
1453        full_name: "ftd#scene".to_string(),
1454        arguments,
1455        locals: Default::default(),
1456        properties: Default::default(),
1457        instructions: Default::default(),
1458        invocations: Default::default(),
1459        condition: None,
1460        events: vec![],
1461    }
1462}
1463
1464pub fn markup_function() -> ftd::Component {
1465    ftd::Component {
1466        line_number: 0,
1467        kernel: true,
1468        root: "ftd.kernel".to_string(),
1469        full_name: "ftd#text".to_string(),
1470        arguments: [
1471            vec![
1472                ("text".to_string(), ftd::p2::Kind::caption_or_body()),
1473                ("align".to_string(), ftd::p2::Kind::string().into_optional()),
1474                ("style".to_string(), ftd::p2::Kind::string().into_optional()),
1475                (
1476                    "role".to_string(),
1477                    ftd::p2::Kind::record("ftd#type").into_optional(),
1478                ),
1479                (
1480                    "line-clamp".to_string(),
1481                    ftd::p2::Kind::integer().into_optional(),
1482                ),
1483                (
1484                    "text-indent".to_string(),
1485                    ftd::p2::Kind::string().into_optional(),
1486                ),
1487                (
1488                    "text-align".to_string(),
1489                    ftd::p2::Kind::string().into_optional(),
1490                ),
1491            ],
1492            common_arguments(),
1493        ]
1494        .concat()
1495        .into_iter()
1496        .collect(),
1497        locals: Default::default(),
1498        properties: Default::default(),
1499        instructions: Default::default(),
1500        invocations: Default::default(),
1501        condition: None,
1502        events: vec![],
1503    }
1504}
1505
1506pub fn grid_function() -> ftd::Component {
1507    let arguments: ftd::Map<ftd::p2::Kind> = [
1508        container_arguments(),
1509        common_arguments(),
1510        vec![
1511            ("slots".to_string(), ftd::p2::Kind::string()),
1512            (
1513                "slot-widths".to_string(),
1514                ftd::p2::Kind::string().into_optional(),
1515            ),
1516            (
1517                "slot-heights".to_string(),
1518                ftd::p2::Kind::string().into_optional(),
1519            ),
1520            (
1521                "spacing".to_string(),
1522                ftd::p2::Kind::integer().into_optional(),
1523            ),
1524            (
1525                "inline".to_string(),
1526                ftd::p2::Kind::boolean().into_optional(),
1527            ),
1528        ],
1529    ]
1530    .concat()
1531    .into_iter()
1532    .collect();
1533
1534    ftd::Component {
1535        line_number: 0,
1536        kernel: true,
1537        root: "ftd.kernel".to_string(),
1538        full_name: "ftd#grid".to_string(),
1539        arguments,
1540        locals: Default::default(),
1541        properties: Default::default(),
1542        instructions: Default::default(),
1543        invocations: Default::default(),
1544        condition: None,
1545        events: vec![],
1546    }
1547}
1548
1549pub fn boolean_function() -> ftd::Component {
1550    ftd::Component {
1551        line_number: 0,
1552        kernel: true,
1553        root: "ftd.kernel".to_string(),
1554        full_name: "ftd#boolean".to_string(),
1555        arguments: [
1556            vec![
1557                ("value".to_string(), ftd::p2::Kind::boolean()),
1558                ("align".to_string(), ftd::p2::Kind::string().into_optional()),
1559                ("style".to_string(), ftd::p2::Kind::string().into_optional()),
1560                (
1561                    "format".to_string(),
1562                    ftd::p2::Kind::string().into_optional(),
1563                ),
1564                (
1565                    "role".to_string(),
1566                    ftd::p2::Kind::record("ftd#type").into_optional(),
1567                ),
1568                ("true".to_string(), ftd::p2::Kind::string().into_optional()),
1569                ("false".to_string(), ftd::p2::Kind::string().into_optional()),
1570            ],
1571            common_arguments(),
1572        ]
1573        .concat()
1574        .into_iter()
1575        .collect(),
1576        locals: Default::default(),
1577        properties: Default::default(),
1578        instructions: Default::default(),
1579        invocations: Default::default(),
1580        condition: None,
1581        events: vec![],
1582    }
1583}
1584
1585pub fn input_function() -> ftd::Component {
1586    ftd::Component {
1587        line_number: 0,
1588        kernel: true,
1589        root: "ftd.kernel".to_string(),
1590        full_name: "ftd#input".to_string(),
1591        arguments: [
1592            vec![
1593                (
1594                    "placeholder".to_string(),
1595                    ftd::p2::Kind::string().into_optional(),
1596                ),
1597                ("value".to_string(), ftd::p2::Kind::string().into_optional()),
1598                (
1599                    "default-value".to_string(),
1600                    ftd::p2::Kind::string().into_optional(),
1601                ),
1602                (
1603                    "multiline".to_string(),
1604                    ftd::p2::Kind::boolean().set_default(Some("false".to_string())),
1605                ),
1606                (
1607                    "role".to_string(),
1608                    ftd::p2::Kind::record("ftd#type").into_optional(),
1609                ),
1610                ("type".to_string(), ftd::p2::Kind::string().into_optional()),
1611            ],
1612            common_arguments(),
1613        ]
1614        .concat()
1615        .into_iter()
1616        .collect(),
1617        locals: Default::default(),
1618        properties: Default::default(),
1619        instructions: Default::default(),
1620        invocations: Default::default(),
1621        condition: None,
1622        events: vec![],
1623    }
1624}
1625
1626pub fn input_from_properties(
1627    unresolved_properties: &ftd::Map<ftd::component::Property>,
1628    doc: &ftd::p2::TDoc,
1629    condition: &Option<ftd::p2::Boolean>,
1630    is_child: bool,
1631    events: &[ftd::p2::Event],
1632) -> ftd::p1::Result<ftd::Input> {
1633    let reference = ftd::p2::utils::string_and_source_and_ref(
1634        0,
1635        "value",
1636        unresolved_properties,
1637        doc,
1638        condition,
1639    )
1640    .map(|v| v.2)
1641    .unwrap_or(None);
1642
1643    let properties = &ftd::component::resolve_properties(0, unresolved_properties, doc)?;
1644    let font_str = ftd::p2::utils::record_optional("role", properties, doc.name, 0)?;
1645    let mut font_reference = None;
1646    if font_str.is_some() {
1647        font_reference =
1648            ftd::p2::utils::record_and_ref(0, "role", unresolved_properties, doc, condition)?.1;
1649    }
1650    let font = font_str.map_or(Ok(None), |v| {
1651        ftd::Type::from(&v, doc, 0, font_reference).map(Some)
1652    })?;
1653
1654    Ok(ftd::Input {
1655        common: common_from_properties(
1656            unresolved_properties,
1657            doc,
1658            condition,
1659            is_child,
1660            events,
1661            reference,
1662        )?,
1663        placeholder: ftd::p2::utils::string_optional("placeholder", properties, doc.name, 0)?,
1664        multiline: ftd::p2::utils::bool_("multiline", properties, doc.name, 0)?,
1665        type_: ftd::p2::utils::string_optional("type", properties, doc.name, 0)?,
1666        value: ftd::p2::utils::string_optional("value", properties, doc.name, 0)?,
1667        default_value: ftd::p2::utils::string_optional("default-value", properties, doc.name, 0)?,
1668        font,
1669    })
1670}
1671
1672pub fn scene_from_properties(
1673    unresolved_properties: &ftd::Map<ftd::component::Property>,
1674    doc: &ftd::p2::TDoc,
1675    condition: &Option<ftd::p2::Boolean>,
1676    is_child: bool,
1677    events: &[ftd::p2::Event],
1678) -> ftd::p1::Result<ftd::Scene> {
1679    let properties = &ftd::component::resolve_properties(0, unresolved_properties, doc)?;
1680    Ok(ftd::Scene {
1681        common: common_from_properties(
1682            unresolved_properties,
1683            doc,
1684            condition,
1685            is_child,
1686            events,
1687            None,
1688        )?,
1689        container: container_from_properties(properties, doc)?,
1690        spacing: ftd::Spacing::from(ftd::p2::utils::string_optional(
1691            "spacing", properties, doc.name, 0,
1692        )?)?,
1693    })
1694}
1695
1696pub fn grid_from_properties(
1697    unresolved_properties: &ftd::Map<ftd::component::Property>,
1698    doc: &ftd::p2::TDoc,
1699    condition: &Option<ftd::p2::Boolean>,
1700    is_child: bool,
1701    events: &[ftd::p2::Event],
1702) -> ftd::p1::Result<ftd::Grid> {
1703    let properties = &ftd::component::resolve_properties(0, unresolved_properties, doc)?;
1704    Ok(ftd::Grid {
1705        slots: match ftd::p2::utils::string_optional("slots", properties, doc.name, 0)? {
1706            Some(val) => val,
1707            None => return ftd::p2::utils::e2("expected slots", doc.name, 0),
1708        },
1709        slot_widths: ftd::p2::utils::string_optional("slot-widths", properties, doc.name, 0)?,
1710        slot_heights: ftd::p2::utils::string_optional("slot-heights", properties, doc.name, 0)?,
1711        spacing: ftd::p2::utils::int_optional("spacing", properties, doc.name, 0)?,
1712        spacing_vertical: ftd::p2::utils::int_optional(
1713            "spacing-vertical",
1714            properties,
1715            doc.name,
1716            0,
1717        )?,
1718        spacing_horizontal: ftd::p2::utils::int_optional(
1719            "spacing-horizontal",
1720            properties,
1721            doc.name,
1722            0,
1723        )?,
1724        common: common_from_properties(
1725            unresolved_properties,
1726            doc,
1727            condition,
1728            is_child,
1729            events,
1730            None,
1731        )?,
1732        container: container_from_properties(properties, doc)?,
1733        inline: ftd::p2::utils::bool_with_default("inline", false, properties, doc.name, 0)?,
1734        auto_flow: ftd::p2::utils::string_optional("auto-flow", properties, doc.name, 0)?,
1735    })
1736}
1737
1738pub fn markup_from_properties(
1739    unresolved_properties: &ftd::Map<ftd::component::Property>,
1740    doc: &ftd::p2::TDoc,
1741    condition: &Option<ftd::p2::Boolean>,
1742    is_child: bool,
1743    events: &[ftd::p2::Event],
1744) -> ftd::p1::Result<ftd::Markups> {
1745    let (value, source, reference) = ftd::p2::utils::string_and_source_and_ref(
1746        0,
1747        "text",
1748        unresolved_properties,
1749        doc,
1750        condition,
1751    )?;
1752    let properties = &ftd::component::resolve_properties(0, unresolved_properties, doc)?;
1753    let font_str = ftd::p2::utils::record_optional("role", properties, doc.name, 0)?;
1754    let mut font_reference = None;
1755    if font_str.is_some() {
1756        font_reference =
1757            ftd::p2::utils::record_and_ref(0, "role", unresolved_properties, doc, condition)?.1;
1758    }
1759    let font = font_str.map_or(Ok(None), |v| {
1760        ftd::Type::from(&v, doc, 0, font_reference).map(Some)
1761    })?;
1762
1763    Ok(ftd::Markups {
1764        text: ftd::rendered::markup_line(value.as_str()),
1765        common: common_from_properties(
1766            unresolved_properties,
1767            doc,
1768            condition,
1769            is_child,
1770            events,
1771            reference,
1772        )?,
1773        children: vec![],
1774        line: source != ftd::TextSource::Body,
1775        text_align: ftd::TextAlign::from(
1776            ftd::p2::utils::string_optional("text-align", properties, doc.name, 0)?,
1777            doc.name,
1778        )?,
1779        style: ftd::Style::from(
1780            ftd::p2::utils::string_optional("style", properties, doc.name, 0)?,
1781            doc.name,
1782        )?,
1783        font,
1784        line_clamp: ftd::p2::utils::int_optional("line-clamp", properties, doc.name, 0)?,
1785        text_indent: ftd::Length::from(
1786            ftd::p2::utils::string_optional("text-indent", properties, doc.name, 0)?,
1787            doc.name,
1788        )?,
1789    })
1790}