@kubuild/components 0.0.1 → 0.2.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/dist/index.js CHANGED
@@ -575,6 +575,341 @@ function buttonTypeTrait(overrides) {
575
575
  overrides
576
576
  );
577
577
  }
578
+ function preventDefaultTrait(overrides) {
579
+ return withOverrides(
580
+ {
581
+ name: "preventDefault",
582
+ label: "Prevent Default",
583
+ type: "boolean",
584
+ defaultValue: true,
585
+ group: "form",
586
+ description: "Intercept the native browser submit and handle it via the KUBUILD action pipeline instead."
587
+ },
588
+ overrides
589
+ );
590
+ }
591
+ function scrollToFirstErrorTrait(overrides) {
592
+ return withOverrides(
593
+ {
594
+ name: "scrollToFirstError",
595
+ label: "Scroll to First Error",
596
+ type: "boolean",
597
+ defaultValue: true,
598
+ group: "form",
599
+ description: "Automatically scroll to and focus the first invalid field when submission fails validation."
600
+ },
601
+ overrides
602
+ );
603
+ }
604
+ function resetOnSubmitTrait(overrides) {
605
+ return withOverrides(
606
+ {
607
+ name: "resetOnSubmit",
608
+ label: "Reset on Submit",
609
+ type: "boolean",
610
+ defaultValue: false,
611
+ group: "form",
612
+ description: "Reset all fields to their initial values after a successful form submission."
613
+ },
614
+ overrides
615
+ );
616
+ }
617
+ function patternTrait(overrides) {
618
+ return withOverrides(
619
+ {
620
+ name: "pattern",
621
+ label: "Pattern (regex)",
622
+ type: "string",
623
+ attribute: "pattern",
624
+ group: "form",
625
+ description: "A regular expression the input value must match to pass validation."
626
+ },
627
+ overrides
628
+ );
629
+ }
630
+ function minLengthTrait(overrides) {
631
+ return withOverrides(
632
+ {
633
+ name: "minLength",
634
+ label: "Min Length",
635
+ type: "number",
636
+ attribute: "minlength",
637
+ group: "form",
638
+ description: "The minimum number of characters the user must enter."
639
+ },
640
+ overrides
641
+ );
642
+ }
643
+ function maxLengthTrait(overrides) {
644
+ return withOverrides(
645
+ {
646
+ name: "maxLength",
647
+ label: "Max Length",
648
+ type: "number",
649
+ attribute: "maxlength",
650
+ group: "form",
651
+ description: "The maximum number of characters the user is allowed to enter."
652
+ },
653
+ overrides
654
+ );
655
+ }
656
+ function prefixIconTrait(overrides) {
657
+ return withOverrides(
658
+ {
659
+ name: "prefixIcon",
660
+ label: "Prefix Icon",
661
+ type: "string",
662
+ group: "form",
663
+ description: 'Lucide icon name displayed before the input value (e.g. "mail", "search").'
664
+ },
665
+ overrides
666
+ );
667
+ }
668
+ function suffixIconTrait(overrides) {
669
+ return withOverrides(
670
+ {
671
+ name: "suffixIcon",
672
+ label: "Suffix Icon",
673
+ type: "string",
674
+ group: "form",
675
+ description: 'Lucide icon name displayed after the input value (e.g. "eye", "check").'
676
+ },
677
+ overrides
678
+ );
679
+ }
680
+ function helperTextTrait(overrides) {
681
+ return withOverrides(
682
+ {
683
+ name: "helperText",
684
+ label: "Helper Text",
685
+ type: "string",
686
+ group: "form",
687
+ description: 'A short message displayed below the input to guide the user (e.g. "Must be at least 8 characters").'
688
+ },
689
+ overrides
690
+ );
691
+ }
692
+ function resizeTrait(overrides) {
693
+ return withOverrides(
694
+ {
695
+ name: "resize",
696
+ label: "Resize",
697
+ type: "select",
698
+ defaultValue: "vertical",
699
+ group: "form",
700
+ options: [
701
+ { label: "Vertical only", value: "vertical" },
702
+ { label: "Horizontal only", value: "horizontal" },
703
+ { label: "Both", value: "both" },
704
+ { label: "None", value: "none" }
705
+ ],
706
+ description: "Controls whether and how the user can resize the textarea."
707
+ },
708
+ overrides
709
+ );
710
+ }
711
+ function autoGrowTrait(overrides) {
712
+ return withOverrides(
713
+ {
714
+ name: "autoGrow",
715
+ label: "Auto Grow",
716
+ type: "boolean",
717
+ defaultValue: false,
718
+ group: "form",
719
+ description: "Automatically expand the textarea height to fit the content without scrolling."
720
+ },
721
+ overrides
722
+ );
723
+ }
724
+ function maxCharCountTrait(overrides) {
725
+ return withOverrides(
726
+ {
727
+ name: "maxCharCount",
728
+ label: "Max Character Count",
729
+ type: "number",
730
+ group: "form",
731
+ description: 'Maximum character limit displayed as a counter below the textarea (e.g. "120 / 500").'
732
+ },
733
+ overrides
734
+ );
735
+ }
736
+ function optionsListTrait(overrides) {
737
+ return withOverrides(
738
+ {
739
+ name: "options",
740
+ label: "Options",
741
+ type: "string",
742
+ group: "form",
743
+ description: "The list of dropdown options, each with a label and value. Editable via the inspector trait panel."
744
+ },
745
+ overrides
746
+ );
747
+ }
748
+ function labelTextTrait(overrides) {
749
+ return withOverrides(
750
+ {
751
+ name: "label",
752
+ label: "Label Text",
753
+ type: "string",
754
+ group: "form",
755
+ description: "The visible text label displayed alongside the control."
756
+ },
757
+ overrides
758
+ );
759
+ }
760
+ function indeterminateTrait(overrides) {
761
+ return withOverrides(
762
+ {
763
+ name: "indeterminate",
764
+ label: "Indeterminate",
765
+ type: "boolean",
766
+ defaultValue: false,
767
+ group: "form",
768
+ description: "Renders the checkbox in a mixed/indeterminate visual state (neither checked nor unchecked)."
769
+ },
770
+ overrides
771
+ );
772
+ }
773
+ function switchSizeTrait(overrides) {
774
+ return withOverrides(
775
+ {
776
+ name: "switchSize",
777
+ label: "Size",
778
+ type: "select",
779
+ defaultValue: "md",
780
+ group: "form",
781
+ options: [
782
+ { label: "Small", value: "sm" },
783
+ { label: "Medium", value: "md" },
784
+ { label: "Large", value: "lg" }
785
+ ],
786
+ description: "The visual size of the switch toggle."
787
+ },
788
+ overrides
789
+ );
790
+ }
791
+ function orientationTrait(overrides) {
792
+ return withOverrides(
793
+ {
794
+ name: "orientation",
795
+ label: "Orientation",
796
+ type: "select",
797
+ defaultValue: "vertical",
798
+ group: "form",
799
+ options: [
800
+ { label: "Vertical", value: "vertical" },
801
+ { label: "Horizontal", value: "horizontal" }
802
+ ],
803
+ description: "The layout direction of the child controls (vertical stack or horizontal row)."
804
+ },
805
+ overrides
806
+ );
807
+ }
808
+ function defaultSelectedTrait(overrides) {
809
+ return withOverrides(
810
+ {
811
+ name: "defaultSelected",
812
+ label: "Default Selected",
813
+ type: "string",
814
+ group: "form",
815
+ description: "The value of the radio item that is selected by default."
816
+ },
817
+ overrides
818
+ );
819
+ }
820
+ function acceptTrait(overrides) {
821
+ return withOverrides(
822
+ {
823
+ name: "accept",
824
+ label: "Accepted File Types",
825
+ type: "string",
826
+ attribute: "accept",
827
+ defaultValue: "*/*",
828
+ group: "form",
829
+ description: 'Comma-separated list of MIME types or file extensions accepted (e.g. "image/*,.pdf,.docx").'
830
+ },
831
+ overrides
832
+ );
833
+ }
834
+ function maxFileSizeTrait(overrides) {
835
+ return withOverrides(
836
+ {
837
+ name: "maxFileSize",
838
+ label: "Max File Size (MB)",
839
+ type: "number",
840
+ defaultValue: 10,
841
+ group: "form",
842
+ description: "The maximum allowable file size in megabytes (MB)."
843
+ },
844
+ overrides
845
+ );
846
+ }
847
+ function multipleTrait(overrides) {
848
+ return withOverrides(
849
+ {
850
+ name: "multiple",
851
+ label: "Allow Multiple Files",
852
+ type: "boolean",
853
+ attribute: "multiple",
854
+ defaultValue: false,
855
+ group: "form",
856
+ description: "Allow multiple files to be selected and uploaded at once."
857
+ },
858
+ overrides
859
+ );
860
+ }
861
+ function showPreviewTrait(overrides) {
862
+ return withOverrides(
863
+ {
864
+ name: "showPreview",
865
+ label: "Show Preview",
866
+ type: "boolean",
867
+ defaultValue: true,
868
+ group: "form",
869
+ description: "Display an interactive preview (image thumbnail or file list with badges) for selected files."
870
+ },
871
+ overrides
872
+ );
873
+ }
874
+ function loadingTextTrait(overrides) {
875
+ return withOverrides(
876
+ {
877
+ name: "loadingText",
878
+ label: "Loading Text",
879
+ type: "string",
880
+ defaultValue: "Submitting...",
881
+ group: "behavior",
882
+ description: "Text displayed on the button while the form submission is in progress."
883
+ },
884
+ overrides
885
+ );
886
+ }
887
+ function showSpinnerTrait(overrides) {
888
+ return withOverrides(
889
+ {
890
+ name: "showSpinner",
891
+ label: "Show Loading Spinner",
892
+ type: "boolean",
893
+ defaultValue: true,
894
+ group: "behavior",
895
+ description: "Automatically show an animated loading spinner icon while form is submitting."
896
+ },
897
+ overrides
898
+ );
899
+ }
900
+ function autoDisableOnSubmitTrait(overrides) {
901
+ return withOverrides(
902
+ {
903
+ name: "autoDisableOnSubmit",
904
+ label: "Auto Disable on Submit",
905
+ type: "boolean",
906
+ defaultValue: true,
907
+ group: "behavior",
908
+ description: "Automatically disable the button to prevent duplicate submissions while the form is submitting."
909
+ },
910
+ overrides
911
+ );
912
+ }
578
913
  function sortTraits(traits) {
579
914
  const groupRank = (group) => {
580
915
  if (!group) return Number.MAX_SAFE_INTEGER;
@@ -608,12 +943,17 @@ var CONTENT_CHILD_TYPES = [
608
943
  "icon",
609
944
  "html-embed",
610
945
  "button",
946
+ "button-submit",
611
947
  "form",
612
948
  "input",
613
949
  "textarea",
614
950
  "select",
615
951
  "checkbox",
952
+ "switch",
953
+ "radio-group",
616
954
  "radio",
955
+ "radio-item",
956
+ "file-upload",
617
957
  "list",
618
958
  "table",
619
959
  "collection",
@@ -1705,7 +2045,10 @@ var formDefinition = {
1705
2045
  method: "POST",
1706
2046
  action: "",
1707
2047
  target: "_self",
1708
- autoComplete: "on"
2048
+ autoComplete: "on",
2049
+ preventDefault: true,
2050
+ scrollToFirstError: true,
2051
+ resetOnSubmit: false
1709
2052
  },
1710
2053
  defaultChildren: [
1711
2054
  { type: "input", props: { name: "name", type: "text", placeholder: "Your Name", required: true } },
@@ -1746,7 +2089,10 @@ var formDefinition = {
1746
2089
  { label: "On", value: "on" },
1747
2090
  { label: "Off", value: "off" }
1748
2091
  ]
1749
- }
2092
+ },
2093
+ { name: "preventDefault", label: "Prevent Default", type: "boolean", defaultValue: true },
2094
+ { name: "scrollToFirstError", label: "Scroll to First Error", type: "boolean", defaultValue: true },
2095
+ { name: "resetOnSubmit", label: "Reset on Submit", type: "boolean", defaultValue: false }
1750
2096
  ],
1751
2097
  traits: [
1752
2098
  fieldNameTrait({ defaultValue: "contact_form", required: false }),
@@ -1759,6 +2105,9 @@ var formDefinition = {
1759
2105
  { label: "Top (_top)", value: "_top" }
1760
2106
  ] }),
1761
2107
  autoCompleteTrait(),
2108
+ preventDefaultTrait(),
2109
+ scrollToFirstErrorTrait(),
2110
+ resetOnSubmitTrait(),
1762
2111
  idTrait(),
1763
2112
  ariaLabelTrait({ description: "Accessible name for the form landmark." })
1764
2113
  ],
@@ -1785,6 +2134,15 @@ var formDefinition = {
1785
2134
  errors.push('Form "autoComplete" must be either "on" or "off".');
1786
2135
  }
1787
2136
  }
2137
+ if (props.preventDefault !== void 0 && typeof props.preventDefault !== "boolean" && !isVariableBinding(props.preventDefault)) {
2138
+ errors.push('Form "preventDefault" must be a boolean when provided.');
2139
+ }
2140
+ if (props.scrollToFirstError !== void 0 && typeof props.scrollToFirstError !== "boolean" && !isVariableBinding(props.scrollToFirstError)) {
2141
+ errors.push('Form "scrollToFirstError" must be a boolean when provided.');
2142
+ }
2143
+ if (props.resetOnSubmit !== void 0 && typeof props.resetOnSubmit !== "boolean" && !isVariableBinding(props.resetOnSubmit)) {
2144
+ errors.push('Form "resetOnSubmit" must be a boolean when provided.');
2145
+ }
1788
2146
  return errors.length > 0 ? errors : true;
1789
2147
  },
1790
2148
  defaultStyles: {
@@ -1810,7 +2168,13 @@ var inputDefinition = {
1810
2168
  defaultValue: "",
1811
2169
  required: false,
1812
2170
  disabled: false,
1813
- readOnly: false
2171
+ readOnly: false,
2172
+ pattern: "",
2173
+ minLength: void 0,
2174
+ maxLength: void 0,
2175
+ prefixIcon: "",
2176
+ suffixIcon: "",
2177
+ helperText: ""
1814
2178
  },
1815
2179
  propFields: [
1816
2180
  { name: "name", label: "Field Name", type: "string", defaultValue: "input_field" },
@@ -1834,7 +2198,13 @@ var inputDefinition = {
1834
2198
  { name: "defaultValue", label: "Default Value", type: "string" },
1835
2199
  { name: "required", label: "Required", type: "boolean", defaultValue: false },
1836
2200
  { name: "disabled", label: "Disabled", type: "boolean", defaultValue: false },
1837
- { name: "readOnly", label: "Read Only", type: "boolean", defaultValue: false }
2201
+ { name: "readOnly", label: "Read Only", type: "boolean", defaultValue: false },
2202
+ { name: "pattern", label: "Pattern (regex)", type: "string" },
2203
+ { name: "minLength", label: "Min Length", type: "number" },
2204
+ { name: "maxLength", label: "Max Length", type: "number" },
2205
+ { name: "prefixIcon", label: "Prefix Icon", type: "string" },
2206
+ { name: "suffixIcon", label: "Suffix Icon", type: "string" },
2207
+ { name: "helperText", label: "Helper Text", type: "string" }
1838
2208
  ],
1839
2209
  traits: [
1840
2210
  inputTypeTrait({ options: [
@@ -1852,6 +2222,12 @@ var inputDefinition = {
1852
2222
  placeholderTrait({ defaultValue: "Enter text..." }),
1853
2223
  defaultValueTrait(),
1854
2224
  requiredTrait(),
2225
+ patternTrait(),
2226
+ minLengthTrait(),
2227
+ maxLengthTrait(),
2228
+ prefixIconTrait(),
2229
+ suffixIconTrait(),
2230
+ helperTextTrait(),
1855
2231
  disabledTrait(),
1856
2232
  readOnlyTrait(),
1857
2233
  idTrait(),
@@ -1880,6 +2256,28 @@ var inputDefinition = {
1880
2256
  if (props.readOnly !== void 0 && typeof props.readOnly !== "boolean" && !isVariableBinding(props.readOnly)) {
1881
2257
  errors.push('Input "readOnly" must be a boolean when provided.');
1882
2258
  }
2259
+ if (props.pattern !== void 0 && typeof props.pattern !== "string" && !isVariableBinding(props.pattern)) {
2260
+ errors.push('Input "pattern" must be a string when provided.');
2261
+ }
2262
+ if (props.minLength !== void 0 && !isVariableBinding(props.minLength)) {
2263
+ if (typeof props.minLength !== "number" || props.minLength < 0 || !Number.isInteger(props.minLength)) {
2264
+ errors.push('Input "minLength" must be a non-negative integer when provided.');
2265
+ }
2266
+ }
2267
+ if (props.maxLength !== void 0 && !isVariableBinding(props.maxLength)) {
2268
+ if (typeof props.maxLength !== "number" || props.maxLength < 0 || !Number.isInteger(props.maxLength)) {
2269
+ errors.push('Input "maxLength" must be a non-negative integer when provided.');
2270
+ }
2271
+ }
2272
+ if (props.prefixIcon !== void 0 && typeof props.prefixIcon !== "string" && !isVariableBinding(props.prefixIcon)) {
2273
+ errors.push('Input "prefixIcon" must be a string when provided.');
2274
+ }
2275
+ if (props.suffixIcon !== void 0 && typeof props.suffixIcon !== "string" && !isVariableBinding(props.suffixIcon)) {
2276
+ errors.push('Input "suffixIcon" must be a string when provided.');
2277
+ }
2278
+ if (props.helperText !== void 0 && typeof props.helperText !== "string" && !isVariableBinding(props.helperText)) {
2279
+ errors.push('Input "helperText" must be a string when provided.');
2280
+ }
1883
2281
  return errors.length > 0 ? errors : true;
1884
2282
  },
1885
2283
  defaultStyles: {
@@ -1914,7 +2312,11 @@ var textareaDefinition = {
1914
2312
  rows: 4,
1915
2313
  required: false,
1916
2314
  disabled: false,
1917
- readOnly: false
2315
+ readOnly: false,
2316
+ resize: "vertical",
2317
+ autoGrow: false,
2318
+ maxCharCount: void 0,
2319
+ helperText: ""
1918
2320
  },
1919
2321
  propFields: [
1920
2322
  { name: "name", label: "Field Name", type: "string", defaultValue: "message" },
@@ -1923,13 +2325,32 @@ var textareaDefinition = {
1923
2325
  { name: "rows", label: "Rows", type: "number", defaultValue: 4 },
1924
2326
  { name: "required", label: "Required", type: "boolean", defaultValue: false },
1925
2327
  { name: "disabled", label: "Disabled", type: "boolean", defaultValue: false },
1926
- { name: "readOnly", label: "Read Only", type: "boolean", defaultValue: false }
2328
+ { name: "readOnly", label: "Read Only", type: "boolean", defaultValue: false },
2329
+ {
2330
+ name: "resize",
2331
+ label: "Resize",
2332
+ type: "select",
2333
+ defaultValue: "vertical",
2334
+ options: [
2335
+ { label: "Vertical only", value: "vertical" },
2336
+ { label: "Horizontal only", value: "horizontal" },
2337
+ { label: "Both", value: "both" },
2338
+ { label: "None", value: "none" }
2339
+ ]
2340
+ },
2341
+ { name: "autoGrow", label: "Auto Grow", type: "boolean", defaultValue: false },
2342
+ { name: "maxCharCount", label: "Max Character Count", type: "number" },
2343
+ { name: "helperText", label: "Helper Text", type: "string" }
1927
2344
  ],
1928
2345
  traits: [
1929
2346
  fieldNameTrait({ defaultValue: "message" }),
1930
2347
  placeholderTrait({ defaultValue: "Enter your message..." }),
1931
2348
  defaultValueTrait(),
1932
2349
  rowsTrait(),
2350
+ resizeTrait(),
2351
+ autoGrowTrait(),
2352
+ maxCharCountTrait(),
2353
+ helperTextTrait(),
1933
2354
  requiredTrait(),
1934
2355
  disabledTrait(),
1935
2356
  readOnlyTrait(),
@@ -1958,6 +2379,23 @@ var textareaDefinition = {
1958
2379
  if (props.readOnly !== void 0 && typeof props.readOnly !== "boolean" && !isVariableBinding(props.readOnly)) {
1959
2380
  errors.push('Textarea "readOnly" must be a boolean when provided.');
1960
2381
  }
2382
+ if (props.resize !== void 0 && !isVariableBinding(props.resize)) {
2383
+ const allowedResize = ["vertical", "horizontal", "both", "none"];
2384
+ if (typeof props.resize !== "string" || !allowedResize.includes(props.resize)) {
2385
+ errors.push(`Textarea "resize" must be one of: ${allowedResize.join(", ")}.`);
2386
+ }
2387
+ }
2388
+ if (props.autoGrow !== void 0 && typeof props.autoGrow !== "boolean" && !isVariableBinding(props.autoGrow)) {
2389
+ errors.push('Textarea "autoGrow" must be a boolean when provided.');
2390
+ }
2391
+ if (props.maxCharCount !== void 0 && !isVariableBinding(props.maxCharCount)) {
2392
+ if (typeof props.maxCharCount !== "number" || props.maxCharCount < 1 || !Number.isInteger(props.maxCharCount)) {
2393
+ errors.push('Textarea "maxCharCount" must be a positive integer (>= 1) when provided.');
2394
+ }
2395
+ }
2396
+ if (props.helperText !== void 0 && typeof props.helperText !== "string" && !isVariableBinding(props.helperText)) {
2397
+ errors.push('Textarea "helperText" must be a string when provided.');
2398
+ }
1961
2399
  return errors.length > 0 ? errors : true;
1962
2400
  },
1963
2401
  defaultStyles: {
@@ -1995,7 +2433,8 @@ var selectDefinition = {
1995
2433
  ],
1996
2434
  defaultValue: "",
1997
2435
  required: false,
1998
- disabled: false
2436
+ disabled: false,
2437
+ helperText: ""
1999
2438
  },
2000
2439
  propFields: [
2001
2440
  { name: "name", label: "Field Name", type: "string", defaultValue: "select_field" },
@@ -2012,12 +2451,15 @@ var selectDefinition = {
2012
2451
  },
2013
2452
  { name: "defaultValue", label: "Default Selected Value", type: "string" },
2014
2453
  { name: "required", label: "Required", type: "boolean", defaultValue: false },
2015
- { name: "disabled", label: "Disabled", type: "boolean", defaultValue: false }
2454
+ { name: "disabled", label: "Disabled", type: "boolean", defaultValue: false },
2455
+ { name: "helperText", label: "Helper Text", type: "string" }
2016
2456
  ],
2017
2457
  traits: [
2018
2458
  fieldNameTrait({ defaultValue: "select_field" }),
2019
2459
  placeholderTrait({ defaultValue: "Select an option..." }),
2460
+ optionsListTrait({ description: "The list of dropdown choices (label + value pairs). Editable via the inspector trait panel." }),
2020
2461
  defaultValueTrait({ description: "The initially selected option value (must match one of the option values)." }),
2462
+ helperTextTrait(),
2021
2463
  requiredTrait(),
2022
2464
  disabledTrait(),
2023
2465
  idTrait(),
@@ -2039,6 +2481,9 @@ var selectDefinition = {
2039
2481
  if (props.disabled !== void 0 && typeof props.disabled !== "boolean" && !isVariableBinding(props.disabled)) {
2040
2482
  errors.push('Select "disabled" must be a boolean when provided.');
2041
2483
  }
2484
+ if (props.helperText !== void 0 && typeof props.helperText !== "string" && !isVariableBinding(props.helperText)) {
2485
+ errors.push('Select "helperText" must be a string when provided.');
2486
+ }
2042
2487
  return errors.length > 0 ? errors : true;
2043
2488
  },
2044
2489
  defaultStyles: {
@@ -2071,21 +2516,28 @@ var checkboxDefinition = {
2071
2516
  label: "I agree to the terms and conditions",
2072
2517
  value: "yes",
2073
2518
  defaultChecked: false,
2519
+ indeterminate: false,
2074
2520
  required: false,
2075
- disabled: false
2521
+ disabled: false,
2522
+ helperText: ""
2076
2523
  },
2077
2524
  propFields: [
2078
2525
  { name: "name", label: "Field Name", type: "string", defaultValue: "checkbox_field" },
2079
2526
  { name: "label", label: "Label Text", type: "string", defaultValue: "I agree to the terms and conditions" },
2080
2527
  { name: "value", label: "Checked Value", type: "string", defaultValue: "yes" },
2081
2528
  { name: "defaultChecked", label: "Default Checked", type: "boolean", defaultValue: false },
2529
+ { name: "indeterminate", label: "Indeterminate", type: "boolean", defaultValue: false },
2082
2530
  { name: "required", label: "Required", type: "boolean", defaultValue: false },
2083
- { name: "disabled", label: "Disabled", type: "boolean", defaultValue: false }
2531
+ { name: "disabled", label: "Disabled", type: "boolean", defaultValue: false },
2532
+ { name: "helperText", label: "Helper Text", type: "string" }
2084
2533
  ],
2085
2534
  traits: [
2086
2535
  fieldNameTrait({ defaultValue: "checkbox_field" }),
2536
+ labelTextTrait({ defaultValue: "I agree to the terms and conditions" }),
2087
2537
  valueTrait({ defaultValue: "yes" }),
2088
2538
  defaultCheckedTrait(),
2539
+ indeterminateTrait(),
2540
+ helperTextTrait(),
2089
2541
  requiredTrait(),
2090
2542
  disabledTrait(),
2091
2543
  idTrait(),
@@ -2105,12 +2557,18 @@ var checkboxDefinition = {
2105
2557
  if (props.defaultChecked !== void 0 && typeof props.defaultChecked !== "boolean" && !isVariableBinding(props.defaultChecked)) {
2106
2558
  errors.push('Checkbox "defaultChecked" must be a boolean when provided.');
2107
2559
  }
2560
+ if (props.indeterminate !== void 0 && typeof props.indeterminate !== "boolean" && !isVariableBinding(props.indeterminate)) {
2561
+ errors.push('Checkbox "indeterminate" must be a boolean when provided.');
2562
+ }
2108
2563
  if (props.required !== void 0 && typeof props.required !== "boolean" && !isVariableBinding(props.required)) {
2109
2564
  errors.push('Checkbox "required" must be a boolean when provided.');
2110
2565
  }
2111
2566
  if (props.disabled !== void 0 && typeof props.disabled !== "boolean" && !isVariableBinding(props.disabled)) {
2112
2567
  errors.push('Checkbox "disabled" must be a boolean when provided.');
2113
2568
  }
2569
+ if (props.helperText !== void 0 && typeof props.helperText !== "string" && !isVariableBinding(props.helperText)) {
2570
+ errors.push('Checkbox "helperText" must be a string when provided.');
2571
+ }
2114
2572
  return errors.length > 0 ? errors : true;
2115
2573
  },
2116
2574
  defaultStyles: {
@@ -2125,20 +2583,194 @@ var checkboxDefinition = {
2125
2583
  }
2126
2584
  }
2127
2585
  };
2128
- var radioDefinition = {
2129
- type: "radio",
2130
- label: "Radio",
2586
+ var switchDefinition = {
2587
+ type: "switch",
2588
+ label: "Switch",
2131
2589
  category: "form",
2132
- icon: "radio",
2590
+ icon: "switch",
2133
2591
  acceptsChildren: false,
2134
2592
  disallowedParents: ["page"],
2135
2593
  defaultProps: {
2136
- name: "radio_group",
2137
- label: "Option 1",
2138
- value: "option1",
2594
+ name: "switch_field",
2595
+ label: "Enable feature",
2596
+ value: "yes",
2139
2597
  defaultChecked: false,
2598
+ switchSize: "md",
2140
2599
  required: false,
2141
- disabled: false
2600
+ disabled: false,
2601
+ helperText: ""
2602
+ },
2603
+ propFields: [
2604
+ { name: "name", label: "Field Name", type: "string", defaultValue: "switch_field" },
2605
+ { name: "label", label: "Label Text", type: "string", defaultValue: "Enable feature" },
2606
+ { name: "value", label: "Checked Value", type: "string", defaultValue: "yes" },
2607
+ { name: "defaultChecked", label: "Default Checked", type: "boolean", defaultValue: false },
2608
+ {
2609
+ name: "switchSize",
2610
+ label: "Size",
2611
+ type: "select",
2612
+ defaultValue: "md",
2613
+ options: [
2614
+ { label: "Small", value: "sm" },
2615
+ { label: "Medium", value: "md" },
2616
+ { label: "Large", value: "lg" }
2617
+ ]
2618
+ },
2619
+ { name: "required", label: "Required", type: "boolean", defaultValue: false },
2620
+ { name: "disabled", label: "Disabled", type: "boolean", defaultValue: false },
2621
+ { name: "helperText", label: "Helper Text", type: "string" }
2622
+ ],
2623
+ traits: [
2624
+ fieldNameTrait({ defaultValue: "switch_field" }),
2625
+ labelTextTrait({ defaultValue: "Enable feature" }),
2626
+ valueTrait({ defaultValue: "yes" }),
2627
+ defaultCheckedTrait(),
2628
+ switchSizeTrait(),
2629
+ helperTextTrait(),
2630
+ requiredTrait(),
2631
+ disabledTrait(),
2632
+ idTrait(),
2633
+ ariaLabelTrait()
2634
+ ],
2635
+ validateProps: (props) => {
2636
+ const errors = [];
2637
+ if (props.label !== void 0 && typeof props.label !== "string" && !isVariableBinding(props.label)) {
2638
+ errors.push('Switch "label" must be a string when provided.');
2639
+ }
2640
+ if (props.name !== void 0 && typeof props.name !== "string" && !isVariableBinding(props.name)) {
2641
+ errors.push('Switch "name" must be a string when provided.');
2642
+ }
2643
+ if (props.value !== void 0 && typeof props.value !== "string" && !isVariableBinding(props.value)) {
2644
+ errors.push('Switch "value" must be a string when provided.');
2645
+ }
2646
+ if (props.defaultChecked !== void 0 && typeof props.defaultChecked !== "boolean" && !isVariableBinding(props.defaultChecked)) {
2647
+ errors.push('Switch "defaultChecked" must be a boolean when provided.');
2648
+ }
2649
+ if (props.switchSize !== void 0 && !isVariableBinding(props.switchSize)) {
2650
+ const allowedSizes = ["sm", "md", "lg"];
2651
+ if (typeof props.switchSize !== "string" || !allowedSizes.includes(props.switchSize)) {
2652
+ errors.push(`Switch "switchSize" must be one of: ${allowedSizes.join(", ")}.`);
2653
+ }
2654
+ }
2655
+ if (props.required !== void 0 && typeof props.required !== "boolean" && !isVariableBinding(props.required)) {
2656
+ errors.push('Switch "required" must be a boolean when provided.');
2657
+ }
2658
+ if (props.disabled !== void 0 && typeof props.disabled !== "boolean" && !isVariableBinding(props.disabled)) {
2659
+ errors.push('Switch "disabled" must be a boolean when provided.');
2660
+ }
2661
+ if (props.helperText !== void 0 && typeof props.helperText !== "string" && !isVariableBinding(props.helperText)) {
2662
+ errors.push('Switch "helperText" must be a string when provided.');
2663
+ }
2664
+ return errors.length > 0 ? errors : true;
2665
+ },
2666
+ defaultStyles: {
2667
+ base: {
2668
+ display: "inline-flex",
2669
+ alignItems: "center",
2670
+ gap: "8px",
2671
+ fontSize: "14px",
2672
+ color: "#1e293b",
2673
+ cursor: "pointer",
2674
+ userSelect: "none"
2675
+ }
2676
+ }
2677
+ };
2678
+ var radioGroupDefinition = {
2679
+ type: "radio-group",
2680
+ label: "Radio Group",
2681
+ category: "form",
2682
+ icon: "radio-group",
2683
+ acceptsChildren: true,
2684
+ allowedChildren: ["radio", "radio-item", "custom"],
2685
+ disallowedParents: ["page"],
2686
+ defaultProps: {
2687
+ name: "radio_group",
2688
+ defaultSelected: "option1",
2689
+ orientation: "vertical",
2690
+ required: false,
2691
+ disabled: false,
2692
+ helperText: ""
2693
+ },
2694
+ defaultChildren: [
2695
+ { type: "radio", props: { name: "radio_group", label: "Option 1", value: "option1", defaultChecked: true } },
2696
+ { type: "radio", props: { name: "radio_group", label: "Option 2", value: "option2", defaultChecked: false } },
2697
+ { type: "radio", props: { name: "radio_group", label: "Option 3", value: "option3", defaultChecked: false } }
2698
+ ],
2699
+ propFields: [
2700
+ { name: "name", label: "Group Name", type: "string", defaultValue: "radio_group" },
2701
+ { name: "defaultSelected", label: "Default Selected", type: "string", defaultValue: "option1" },
2702
+ {
2703
+ name: "orientation",
2704
+ label: "Orientation",
2705
+ type: "select",
2706
+ defaultValue: "vertical",
2707
+ options: [
2708
+ { label: "Vertical", value: "vertical" },
2709
+ { label: "Horizontal", value: "horizontal" }
2710
+ ]
2711
+ },
2712
+ { name: "required", label: "Required", type: "boolean", defaultValue: false },
2713
+ { name: "disabled", label: "Disabled", type: "boolean", defaultValue: false },
2714
+ { name: "helperText", label: "Helper Text", type: "string" }
2715
+ ],
2716
+ traits: [
2717
+ fieldNameTrait({ defaultValue: "radio_group", label: "Group Name" }),
2718
+ defaultSelectedTrait({ defaultValue: "option1" }),
2719
+ orientationTrait(),
2720
+ helperTextTrait(),
2721
+ requiredTrait(),
2722
+ disabledTrait(),
2723
+ idTrait(),
2724
+ ariaLabelTrait()
2725
+ ],
2726
+ validateProps: (props) => {
2727
+ const errors = [];
2728
+ if (props.name !== void 0 && typeof props.name !== "string" && !isVariableBinding(props.name)) {
2729
+ errors.push('RadioGroup "name" must be a string when provided.');
2730
+ }
2731
+ if (props.defaultSelected !== void 0 && typeof props.defaultSelected !== "string" && !isVariableBinding(props.defaultSelected)) {
2732
+ errors.push('RadioGroup "defaultSelected" must be a string when provided.');
2733
+ }
2734
+ if (props.orientation !== void 0 && !isVariableBinding(props.orientation)) {
2735
+ const allowedOrientations = ["vertical", "horizontal"];
2736
+ if (typeof props.orientation !== "string" || !allowedOrientations.includes(props.orientation)) {
2737
+ errors.push(`RadioGroup "orientation" must be one of: ${allowedOrientations.join(", ")}.`);
2738
+ }
2739
+ }
2740
+ if (props.required !== void 0 && typeof props.required !== "boolean" && !isVariableBinding(props.required)) {
2741
+ errors.push('RadioGroup "required" must be a boolean when provided.');
2742
+ }
2743
+ if (props.disabled !== void 0 && typeof props.disabled !== "boolean" && !isVariableBinding(props.disabled)) {
2744
+ errors.push('RadioGroup "disabled" must be a boolean when provided.');
2745
+ }
2746
+ if (props.helperText !== void 0 && typeof props.helperText !== "string" && !isVariableBinding(props.helperText)) {
2747
+ errors.push('RadioGroup "helperText" must be a string when provided.');
2748
+ }
2749
+ return errors.length > 0 ? errors : true;
2750
+ },
2751
+ defaultStyles: {
2752
+ base: {
2753
+ display: "flex",
2754
+ flexDirection: "column",
2755
+ gap: "8px"
2756
+ }
2757
+ }
2758
+ };
2759
+ var radioDefinition = {
2760
+ type: "radio",
2761
+ label: "Radio",
2762
+ category: "form",
2763
+ icon: "radio",
2764
+ acceptsChildren: false,
2765
+ disallowedParents: ["page"],
2766
+ defaultProps: {
2767
+ name: "radio_group",
2768
+ label: "Option 1",
2769
+ value: "option1",
2770
+ defaultChecked: false,
2771
+ required: false,
2772
+ disabled: false,
2773
+ helperText: ""
2142
2774
  },
2143
2775
  propFields: [
2144
2776
  { name: "name", label: "Group Name", type: "string", defaultValue: "radio_group" },
@@ -2146,12 +2778,15 @@ var radioDefinition = {
2146
2778
  { name: "value", label: "Radio Value", type: "string", defaultValue: "option1" },
2147
2779
  { name: "defaultChecked", label: "Default Selected", type: "boolean", defaultValue: false },
2148
2780
  { name: "required", label: "Required", type: "boolean", defaultValue: false },
2149
- { name: "disabled", label: "Disabled", type: "boolean", defaultValue: false }
2781
+ { name: "disabled", label: "Disabled", type: "boolean", defaultValue: false },
2782
+ { name: "helperText", label: "Helper Text", type: "string" }
2150
2783
  ],
2151
2784
  traits: [
2152
2785
  fieldNameTrait({ defaultValue: "radio_group", label: "Group Name" }),
2786
+ labelTextTrait({ defaultValue: "Option 1" }),
2153
2787
  valueTrait({ defaultValue: "option1" }),
2154
2788
  defaultCheckedTrait(),
2789
+ helperTextTrait(),
2155
2790
  requiredTrait(),
2156
2791
  disabledTrait(),
2157
2792
  idTrait(),
@@ -2177,6 +2812,9 @@ var radioDefinition = {
2177
2812
  if (props.disabled !== void 0 && typeof props.disabled !== "boolean" && !isVariableBinding(props.disabled)) {
2178
2813
  errors.push('Radio "disabled" must be a boolean when provided.');
2179
2814
  }
2815
+ if (props.helperText !== void 0 && typeof props.helperText !== "string" && !isVariableBinding(props.helperText)) {
2816
+ errors.push('Radio "helperText" must be a string when provided.');
2817
+ }
2180
2818
  return errors.length > 0 ? errors : true;
2181
2819
  },
2182
2820
  defaultStyles: {
@@ -2191,6 +2829,206 @@ var radioDefinition = {
2191
2829
  }
2192
2830
  }
2193
2831
  };
2832
+ var radioItemDefinition = {
2833
+ ...radioDefinition,
2834
+ type: "radio-item",
2835
+ label: "Radio Item"
2836
+ };
2837
+ var fileUploadDefinition = {
2838
+ type: "file-upload",
2839
+ label: "File Upload",
2840
+ category: "form",
2841
+ icon: "upload",
2842
+ acceptsChildren: false,
2843
+ disallowedParents: ["page"],
2844
+ defaultProps: {
2845
+ name: "file_upload",
2846
+ label: "Upload File",
2847
+ accept: "*/*",
2848
+ maxFileSize: 10,
2849
+ multiple: false,
2850
+ showPreview: true,
2851
+ required: false,
2852
+ disabled: false,
2853
+ helperText: ""
2854
+ },
2855
+ propFields: [
2856
+ { name: "name", label: "Field Name", type: "string", defaultValue: "file_upload" },
2857
+ { name: "label", label: "Label Text", type: "string", defaultValue: "Upload File" },
2858
+ { name: "accept", label: "Accepted File Types", type: "string", defaultValue: "*/*" },
2859
+ { name: "maxFileSize", label: "Max File Size (MB)", type: "number", defaultValue: 10 },
2860
+ { name: "multiple", label: "Allow Multiple Files", type: "boolean", defaultValue: false },
2861
+ { name: "showPreview", label: "Show Preview", type: "boolean", defaultValue: true },
2862
+ { name: "required", label: "Required", type: "boolean", defaultValue: false },
2863
+ { name: "disabled", label: "Disabled", type: "boolean", defaultValue: false },
2864
+ { name: "helperText", label: "Helper Text", type: "string" }
2865
+ ],
2866
+ traits: [
2867
+ fieldNameTrait({ defaultValue: "file_upload" }),
2868
+ labelTextTrait({ defaultValue: "Upload File" }),
2869
+ acceptTrait(),
2870
+ maxFileSizeTrait(),
2871
+ multipleTrait(),
2872
+ showPreviewTrait(),
2873
+ helperTextTrait(),
2874
+ requiredTrait(),
2875
+ disabledTrait(),
2876
+ idTrait(),
2877
+ ariaLabelTrait()
2878
+ ],
2879
+ validateProps: (props) => {
2880
+ const errors = [];
2881
+ if (props.label !== void 0 && typeof props.label !== "string" && !isVariableBinding(props.label)) {
2882
+ errors.push('FileUpload "label" must be a string when provided.');
2883
+ }
2884
+ if (props.name !== void 0 && typeof props.name !== "string" && !isVariableBinding(props.name)) {
2885
+ errors.push('FileUpload "name" must be a string when provided.');
2886
+ }
2887
+ if (props.accept !== void 0 && typeof props.accept !== "string" && !isVariableBinding(props.accept)) {
2888
+ errors.push('FileUpload "accept" must be a string when provided.');
2889
+ }
2890
+ if (props.maxFileSize !== void 0 && !isVariableBinding(props.maxFileSize)) {
2891
+ if (typeof props.maxFileSize !== "number" || props.maxFileSize <= 0) {
2892
+ errors.push('FileUpload "maxFileSize" must be a positive number when provided.');
2893
+ }
2894
+ }
2895
+ if (props.multiple !== void 0 && typeof props.multiple !== "boolean" && !isVariableBinding(props.multiple)) {
2896
+ errors.push('FileUpload "multiple" must be a boolean when provided.');
2897
+ }
2898
+ if (props.showPreview !== void 0 && typeof props.showPreview !== "boolean" && !isVariableBinding(props.showPreview)) {
2899
+ errors.push('FileUpload "showPreview" must be a boolean when provided.');
2900
+ }
2901
+ if (props.required !== void 0 && typeof props.required !== "boolean" && !isVariableBinding(props.required)) {
2902
+ errors.push('FileUpload "required" must be a boolean when provided.');
2903
+ }
2904
+ if (props.disabled !== void 0 && typeof props.disabled !== "boolean" && !isVariableBinding(props.disabled)) {
2905
+ errors.push('FileUpload "disabled" must be a boolean when provided.');
2906
+ }
2907
+ if (props.helperText !== void 0 && typeof props.helperText !== "string" && !isVariableBinding(props.helperText)) {
2908
+ errors.push('FileUpload "helperText" must be a string when provided.');
2909
+ }
2910
+ return errors.length > 0 ? errors : true;
2911
+ },
2912
+ defaultStyles: {
2913
+ base: {
2914
+ display: "flex",
2915
+ flexDirection: "column",
2916
+ gap: "8px",
2917
+ fontSize: "14px",
2918
+ color: "#1e293b"
2919
+ }
2920
+ }
2921
+ };
2922
+ var buttonSubmitDefinition = {
2923
+ type: "button-submit",
2924
+ label: "Submit Button",
2925
+ category: "form",
2926
+ icon: "send",
2927
+ acceptsChildren: false,
2928
+ capabilities: ["actionRegistry"],
2929
+ disallowedParents: ["page"],
2930
+ defaultProps: {
2931
+ label: "Submit",
2932
+ loadingText: "Submitting...",
2933
+ showSpinner: true,
2934
+ autoDisableOnSubmit: true,
2935
+ variant: "primary",
2936
+ disabled: false,
2937
+ buttonType: "submit"
2938
+ },
2939
+ propFields: [
2940
+ { name: "label", label: "Label", type: "string", defaultValue: "Submit" },
2941
+ { name: "loadingText", label: "Loading Text", type: "string", defaultValue: "Submitting..." },
2942
+ { name: "showSpinner", label: "Show Loading Spinner", type: "boolean", defaultValue: true },
2943
+ { name: "autoDisableOnSubmit", label: "Auto Disable on Submit", type: "boolean", defaultValue: true },
2944
+ {
2945
+ name: "buttonType",
2946
+ label: "Button Type",
2947
+ type: "select",
2948
+ defaultValue: "submit",
2949
+ options: [
2950
+ { label: "Submit Form (submit)", value: "submit" },
2951
+ { label: "Reset Form (reset)", value: "reset" }
2952
+ ]
2953
+ },
2954
+ {
2955
+ name: "variant",
2956
+ label: "Variant",
2957
+ type: "select",
2958
+ defaultValue: "primary",
2959
+ options: [
2960
+ { label: "Primary", value: "primary" },
2961
+ { label: "Secondary", value: "secondary" }
2962
+ ]
2963
+ },
2964
+ { name: "disabled", label: "Disabled", type: "boolean", defaultValue: false },
2965
+ { name: "prefixIcon", label: "Prefix Icon", type: "string" },
2966
+ { name: "suffixIcon", label: "Suffix Icon", type: "string" }
2967
+ ],
2968
+ traits: [
2969
+ buttonTypeTrait({
2970
+ defaultValue: "submit",
2971
+ options: [
2972
+ { label: "Submit Form (submit)", value: "submit" },
2973
+ { label: "Reset Form (reset)", value: "reset" }
2974
+ ]
2975
+ }),
2976
+ labelTextTrait({ defaultValue: "Submit", label: "Label" }),
2977
+ loadingTextTrait(),
2978
+ showSpinnerTrait(),
2979
+ autoDisableOnSubmitTrait(),
2980
+ disabledTrait(),
2981
+ prefixIconTrait(),
2982
+ suffixIconTrait(),
2983
+ idTrait(),
2984
+ titleTrait(),
2985
+ ariaLabelTrait()
2986
+ ],
2987
+ validateProps: (props) => {
2988
+ const errors = [];
2989
+ const hasLabel = typeof props.label === "string" && props.label.trim().length > 0 || isVariableBinding(props.label);
2990
+ if (!hasLabel) {
2991
+ errors.push('Submit Button requires a non-empty "label".');
2992
+ }
2993
+ if (props.loadingText !== void 0 && typeof props.loadingText !== "string" && !isVariableBinding(props.loadingText)) {
2994
+ errors.push('Submit Button "loadingText" must be a string when provided.');
2995
+ }
2996
+ if (props.showSpinner !== void 0 && typeof props.showSpinner !== "boolean" && !isVariableBinding(props.showSpinner)) {
2997
+ errors.push('Submit Button "showSpinner" must be a boolean when provided.');
2998
+ }
2999
+ if (props.autoDisableOnSubmit !== void 0 && typeof props.autoDisableOnSubmit !== "boolean" && !isVariableBinding(props.autoDisableOnSubmit)) {
3000
+ errors.push('Submit Button "autoDisableOnSubmit" must be a boolean when provided.');
3001
+ }
3002
+ if (props.buttonType !== void 0 && !isVariableBinding(props.buttonType)) {
3003
+ if (!["submit", "reset", "button"].includes(props.buttonType)) {
3004
+ errors.push('Submit Button "buttonType" must be one of: "submit", "reset", "button".');
3005
+ }
3006
+ }
3007
+ if (props.disabled !== void 0 && typeof props.disabled !== "boolean" && !isVariableBinding(props.disabled)) {
3008
+ errors.push('Submit Button "disabled" must be a boolean when provided.');
3009
+ }
3010
+ return errors.length > 0 ? errors : true;
3011
+ },
3012
+ defaultStyles: {
3013
+ base: {
3014
+ backgroundColor: "#2563eb",
3015
+ color: "#ffffff",
3016
+ paddingTop: "10px",
3017
+ paddingBottom: "10px",
3018
+ paddingLeft: "20px",
3019
+ paddingRight: "20px",
3020
+ borderRadius: "6px",
3021
+ fontWeight: "500",
3022
+ fontSize: "15px",
3023
+ border: "none",
3024
+ cursor: "pointer",
3025
+ display: "inline-flex",
3026
+ alignItems: "center",
3027
+ justifyContent: "center",
3028
+ gap: "8px"
3029
+ }
3030
+ }
3031
+ };
2194
3032
  var coreComponentDefinitions = [
2195
3033
  pageDefinition,
2196
3034
  sectionDefinition,
@@ -2208,12 +3046,17 @@ var coreComponentDefinitions = [
2208
3046
  iconDefinition,
2209
3047
  htmlEmbedDefinition,
2210
3048
  buttonDefinition,
3049
+ buttonSubmitDefinition,
2211
3050
  formDefinition,
2212
3051
  inputDefinition,
2213
3052
  textareaDefinition,
2214
3053
  selectDefinition,
2215
3054
  checkboxDefinition,
3055
+ switchDefinition,
3056
+ radioGroupDefinition,
2216
3057
  radioDefinition,
3058
+ radioItemDefinition,
3059
+ fileUploadDefinition,
2217
3060
  collectionDefinition,
2218
3061
  listDefinition,
2219
3062
  listItemDefinition,
@@ -2268,18 +3111,1290 @@ function primitiveTypeForField(field) {
2268
3111
  function isBindableField(field) {
2269
3112
  return primitiveTypeForField(field) !== void 0;
2270
3113
  }
3114
+
3115
+ // src/blocks.ts
3116
+ var nextId = 1;
3117
+ function defaultGenId(prefix = "node") {
3118
+ return `${prefix}-${Date.now().toString(36)}-${(nextId++).toString(36)}`;
3119
+ }
3120
+ var STARTER_BLOCKS = [
3121
+ // --- Layout Blocks (STORA-241) ---
3122
+ {
3123
+ id: "layout-1-col",
3124
+ name: "1 Column",
3125
+ category: "layout",
3126
+ categoryLabel: "Layout Blocks",
3127
+ description: "Full-width single column container inside a section",
3128
+ icon: "layout",
3129
+ createNodeTree: (gen = defaultGenId) => ({
3130
+ id: gen("section"),
3131
+ type: "section",
3132
+ styles: { base: { padding: "40px 20px", width: "100%" } },
3133
+ children: [
3134
+ {
3135
+ id: gen("container"),
3136
+ type: "container",
3137
+ props: { tag: "div" },
3138
+ styles: { base: { maxWidth: "1200px", margin: "0 auto", width: "100%" } },
3139
+ children: []
3140
+ }
3141
+ ]
3142
+ })
3143
+ },
3144
+ {
3145
+ id: "layout-2-col-50-50",
3146
+ name: "2 Columns (50/50)",
3147
+ category: "layout",
3148
+ categoryLabel: "Layout Blocks",
3149
+ description: "Two equal-width 50/50 columns with flexible layout",
3150
+ icon: "columns",
3151
+ createNodeTree: (gen = defaultGenId) => ({
3152
+ id: gen("section"),
3153
+ type: "section",
3154
+ styles: { base: { padding: "40px 20px", width: "100%" } },
3155
+ children: [
3156
+ {
3157
+ id: gen("columns"),
3158
+ type: "columns",
3159
+ props: { columns: 2, gap: "24px" },
3160
+ styles: { base: { display: "flex", gap: "24px", width: "100%", maxWidth: "1200px", margin: "0 auto" } },
3161
+ children: [
3162
+ {
3163
+ id: gen("container"),
3164
+ type: "container",
3165
+ props: { tag: "div" },
3166
+ styles: { base: { flex: "1 1 0%", minWidth: "0" } },
3167
+ children: []
3168
+ },
3169
+ {
3170
+ id: gen("container"),
3171
+ type: "container",
3172
+ props: { tag: "div" },
3173
+ styles: { base: { flex: "1 1 0%", minWidth: "0" } },
3174
+ children: []
3175
+ }
3176
+ ]
3177
+ }
3178
+ ]
3179
+ })
3180
+ },
3181
+ {
3182
+ id: "layout-2-col-30-70",
3183
+ name: "2 Columns (30/70)",
3184
+ category: "layout",
3185
+ categoryLabel: "Layout Blocks",
3186
+ description: "Two asymmetric columns: 30% sidebar and 70% main area",
3187
+ icon: "columns",
3188
+ createNodeTree: (gen = defaultGenId) => ({
3189
+ id: gen("section"),
3190
+ type: "section",
3191
+ styles: { base: { padding: "40px 20px", width: "100%" } },
3192
+ children: [
3193
+ {
3194
+ id: gen("columns"),
3195
+ type: "columns",
3196
+ props: { columns: 2, gap: "24px" },
3197
+ styles: { base: { display: "flex", gap: "24px", width: "100%", maxWidth: "1200px", margin: "0 auto" } },
3198
+ children: [
3199
+ {
3200
+ id: gen("container"),
3201
+ type: "container",
3202
+ props: { tag: "div" },
3203
+ styles: { base: { flex: "0 0 30%", minWidth: "0" } },
3204
+ children: []
3205
+ },
3206
+ {
3207
+ id: gen("container"),
3208
+ type: "container",
3209
+ props: { tag: "div" },
3210
+ styles: { base: { flex: "1 1 0%", minWidth: "0" } },
3211
+ children: []
3212
+ }
3213
+ ]
3214
+ }
3215
+ ]
3216
+ })
3217
+ },
3218
+ {
3219
+ id: "layout-3-col",
3220
+ name: "3 Columns",
3221
+ category: "layout",
3222
+ categoryLabel: "Layout Blocks",
3223
+ description: "Three equal-width columns for grid showcases or card groups",
3224
+ icon: "grid",
3225
+ createNodeTree: (gen = defaultGenId) => ({
3226
+ id: gen("section"),
3227
+ type: "section",
3228
+ styles: { base: { padding: "40px 20px", width: "100%" } },
3229
+ children: [
3230
+ {
3231
+ id: gen("columns"),
3232
+ type: "columns",
3233
+ props: { columns: 3, gap: "24px" },
3234
+ styles: { base: { display: "flex", gap: "24px", width: "100%", maxWidth: "1200px", margin: "0 auto" } },
3235
+ children: [
3236
+ {
3237
+ id: gen("container"),
3238
+ type: "container",
3239
+ props: { tag: "div" },
3240
+ styles: { base: { flex: "1 1 0%", minWidth: "0" } },
3241
+ children: []
3242
+ },
3243
+ {
3244
+ id: gen("container"),
3245
+ type: "container",
3246
+ props: { tag: "div" },
3247
+ styles: { base: { flex: "1 1 0%", minWidth: "0" } },
3248
+ children: []
3249
+ },
3250
+ {
3251
+ id: gen("container"),
3252
+ type: "container",
3253
+ props: { tag: "div" },
3254
+ styles: { base: { flex: "1 1 0%", minWidth: "0" } },
3255
+ children: []
3256
+ }
3257
+ ]
3258
+ }
3259
+ ]
3260
+ })
3261
+ },
3262
+ {
3263
+ id: "layout-4-col",
3264
+ name: "4 Columns",
3265
+ category: "layout",
3266
+ categoryLabel: "Layout Blocks",
3267
+ description: "Four equal columns for metric stats, logos, or compact feature cards",
3268
+ icon: "grid",
3269
+ createNodeTree: (gen = defaultGenId) => ({
3270
+ id: gen("section"),
3271
+ type: "section",
3272
+ styles: { base: { padding: "40px 20px", width: "100%" } },
3273
+ children: [
3274
+ {
3275
+ id: gen("columns"),
3276
+ type: "columns",
3277
+ props: { columns: 4, gap: "16px" },
3278
+ styles: { base: { display: "flex", gap: "16px", width: "100%", maxWidth: "1200px", margin: "0 auto" } },
3279
+ children: [
3280
+ {
3281
+ id: gen("container"),
3282
+ type: "container",
3283
+ props: { tag: "div" },
3284
+ styles: { base: { flex: "1 1 0%", minWidth: "0" } },
3285
+ children: []
3286
+ },
3287
+ {
3288
+ id: gen("container"),
3289
+ type: "container",
3290
+ props: { tag: "div" },
3291
+ styles: { base: { flex: "1 1 0%", minWidth: "0" } },
3292
+ children: []
3293
+ },
3294
+ {
3295
+ id: gen("container"),
3296
+ type: "container",
3297
+ props: { tag: "div" },
3298
+ styles: { base: { flex: "1 1 0%", minWidth: "0" } },
3299
+ children: []
3300
+ },
3301
+ {
3302
+ id: gen("container"),
3303
+ type: "container",
3304
+ props: { tag: "div" },
3305
+ styles: { base: { flex: "1 1 0%", minWidth: "0" } },
3306
+ children: []
3307
+ }
3308
+ ]
3309
+ }
3310
+ ]
3311
+ })
3312
+ },
3313
+ // --- Pre-composed UI Blocks (STORA-242) ---
3314
+ {
3315
+ id: "hero-section",
3316
+ name: "Hero Section",
3317
+ category: "sections",
3318
+ categoryLabel: "Hero & Headers",
3319
+ description: "Engaging hero banner with headline, lead paragraph, and call-to-action button",
3320
+ icon: "layout",
3321
+ createNodeTree: (gen = defaultGenId) => ({
3322
+ id: gen("section"),
3323
+ type: "section",
3324
+ styles: {
3325
+ base: {
3326
+ padding: "80px 24px",
3327
+ backgroundColor: "#f8fafc",
3328
+ textAlign: "center",
3329
+ width: "100%"
3330
+ }
3331
+ },
3332
+ children: [
3333
+ {
3334
+ id: gen("container"),
3335
+ type: "container",
3336
+ props: { tag: "div" },
3337
+ styles: { base: { maxWidth: "768px", margin: "0 auto" } },
3338
+ children: [
3339
+ {
3340
+ id: gen("heading"),
3341
+ type: "heading",
3342
+ props: { text: "Build Remarkable Experiences", level: 1 },
3343
+ styles: {
3344
+ base: {
3345
+ fontSize: "44px",
3346
+ fontWeight: "800",
3347
+ color: "#0f172a",
3348
+ marginBottom: "16px",
3349
+ lineHeight: "1.2"
3350
+ }
3351
+ }
3352
+ },
3353
+ {
3354
+ id: gen("paragraph"),
3355
+ type: "paragraph",
3356
+ props: {
3357
+ content: "A visual builder designed for maximum craft, responsiveness, and performance."
3358
+ },
3359
+ styles: {
3360
+ base: {
3361
+ fontSize: "18px",
3362
+ color: "#475569",
3363
+ marginBottom: "32px",
3364
+ lineHeight: "1.6"
3365
+ }
3366
+ }
3367
+ },
3368
+ {
3369
+ id: gen("button"),
3370
+ type: "button",
3371
+ props: { label: "Get Started Today", href: "#explore" },
3372
+ styles: {
3373
+ base: {
3374
+ backgroundColor: "#2563eb",
3375
+ color: "#ffffff",
3376
+ padding: "12px 28px",
3377
+ borderRadius: "8px",
3378
+ fontWeight: "600",
3379
+ display: "inline-block"
3380
+ },
3381
+ states: {
3382
+ ":hover": { backgroundColor: "#1d4ed8" }
3383
+ }
3384
+ }
3385
+ }
3386
+ ]
3387
+ }
3388
+ ]
3389
+ })
3390
+ },
3391
+ {
3392
+ id: "feature-card",
3393
+ name: "Feature Card",
3394
+ category: "ui",
3395
+ categoryLabel: "UI Blocks",
3396
+ description: "Clean elevated feature card with badge, title, text, and action link",
3397
+ icon: "box",
3398
+ createNodeTree: (gen = defaultGenId) => ({
3399
+ id: gen("container"),
3400
+ type: "container",
3401
+ props: { tag: "div" },
3402
+ styles: {
3403
+ base: {
3404
+ padding: "24px",
3405
+ backgroundColor: "#ffffff",
3406
+ borderRadius: "12px",
3407
+ border: "1px solid #e2e8f0",
3408
+ boxShadow: "0 4px 6px -1px rgba(0, 0, 0, 0.05)"
3409
+ }
3410
+ },
3411
+ children: [
3412
+ {
3413
+ id: gen("badge"),
3414
+ type: "badge",
3415
+ props: { label: "PRO FEATURE", variant: "primary" },
3416
+ styles: { base: { marginBottom: "12px", display: "inline-block" } }
3417
+ },
3418
+ {
3419
+ id: gen("heading"),
3420
+ type: "heading",
3421
+ props: { text: "Next-Gen Performance", level: 3 },
3422
+ styles: {
3423
+ base: { fontSize: "20px", fontWeight: "700", color: "#1e293b", marginBottom: "8px" }
3424
+ }
3425
+ },
3426
+ {
3427
+ id: gen("paragraph"),
3428
+ type: "paragraph",
3429
+ props: {
3430
+ content: "Engineered for sub-millisecond render updates and zero runtime overhead."
3431
+ },
3432
+ styles: { base: { fontSize: "14px", color: "#64748b", lineHeight: "1.5" } }
3433
+ }
3434
+ ]
3435
+ })
3436
+ },
3437
+ {
3438
+ id: "media-object",
3439
+ name: "Media Object",
3440
+ category: "ui",
3441
+ categoryLabel: "UI Blocks",
3442
+ description: "Horizontal media layout with image beside text content",
3443
+ icon: "image",
3444
+ createNodeTree: (gen = defaultGenId) => ({
3445
+ id: gen("container"),
3446
+ type: "container",
3447
+ props: { tag: "div" },
3448
+ styles: {
3449
+ base: {
3450
+ display: "flex",
3451
+ gap: "16px",
3452
+ alignItems: "flex-start",
3453
+ padding: "16px",
3454
+ backgroundColor: "#ffffff",
3455
+ borderRadius: "8px",
3456
+ border: "1px solid #e2e8f0"
3457
+ }
3458
+ },
3459
+ children: [
3460
+ {
3461
+ id: gen("image"),
3462
+ type: "image",
3463
+ props: {
3464
+ src: "https://images.unsplash.com/photo-1579546929518-9e396f3cc809?w=160&auto=format&fit=crop&q=80",
3465
+ alt: "Visual preview"
3466
+ },
3467
+ styles: {
3468
+ base: {
3469
+ width: "80px",
3470
+ height: "80px",
3471
+ borderRadius: "8px",
3472
+ objectFit: "cover",
3473
+ flexShrink: "0"
3474
+ }
3475
+ }
3476
+ },
3477
+ {
3478
+ id: gen("container"),
3479
+ type: "container",
3480
+ props: { tag: "div" },
3481
+ styles: { base: { flex: "1 1 0%" } },
3482
+ children: [
3483
+ {
3484
+ id: gen("heading"),
3485
+ type: "heading",
3486
+ props: { text: "Creative Studio Asset", level: 4 },
3487
+ styles: {
3488
+ base: { fontSize: "16px", fontWeight: "600", color: "#0f172a", marginBottom: "4px" }
3489
+ }
3490
+ },
3491
+ {
3492
+ id: gen("paragraph"),
3493
+ type: "paragraph",
3494
+ props: { content: "High dynamic range gradients crafted for modern presentations." },
3495
+ styles: { base: { fontSize: "13px", color: "#64748b", lineHeight: "1.4" } }
3496
+ }
3497
+ ]
3498
+ }
3499
+ ]
3500
+ })
3501
+ },
3502
+ {
3503
+ id: "pricing-table",
3504
+ name: "Pricing Table",
3505
+ category: "pricing",
3506
+ categoryLabel: "Pricing",
3507
+ description: "Highlighted subscription pricing plan with price, feature list, and buy button",
3508
+ icon: "table",
3509
+ createNodeTree: (gen = defaultGenId) => ({
3510
+ id: gen("container"),
3511
+ type: "container",
3512
+ props: { tag: "div" },
3513
+ styles: {
3514
+ base: {
3515
+ padding: "32px 24px",
3516
+ backgroundColor: "#ffffff",
3517
+ borderRadius: "16px",
3518
+ border: "2px solid #3b82f6",
3519
+ boxShadow: "0 10px 15px -3px rgba(59, 130, 246, 0.1)",
3520
+ textAlign: "center",
3521
+ maxWidth: "360px"
3522
+ }
3523
+ },
3524
+ children: [
3525
+ {
3526
+ id: gen("badge"),
3527
+ type: "badge",
3528
+ props: { label: "MOST POPULAR", variant: "primary" },
3529
+ styles: { base: { marginBottom: "12px", display: "inline-block" } }
3530
+ },
3531
+ {
3532
+ id: gen("heading"),
3533
+ type: "heading",
3534
+ props: { text: "Professional", level: 3 },
3535
+ styles: { base: { fontSize: "22px", fontWeight: "700", color: "#0f172a" } }
3536
+ },
3537
+ {
3538
+ id: gen("heading"),
3539
+ type: "heading",
3540
+ props: { text: "$29 / mo", level: 2 },
3541
+ styles: {
3542
+ base: { fontSize: "36px", fontWeight: "800", color: "#2563eb", margin: "16px 0 24px 0" }
3543
+ }
3544
+ },
3545
+ {
3546
+ id: gen("paragraph"),
3547
+ type: "paragraph",
3548
+ props: { content: "Includes unlimited pages, custom domains, and team collaboration." },
3549
+ styles: { base: { fontSize: "14px", color: "#64748b", marginBottom: "24px" } }
3550
+ },
3551
+ {
3552
+ id: gen("button"),
3553
+ type: "button",
3554
+ props: { label: "Upgrade to Pro", href: "#checkout" },
3555
+ styles: {
3556
+ base: {
3557
+ width: "100%",
3558
+ backgroundColor: "#2563eb",
3559
+ color: "#ffffff",
3560
+ padding: "12px",
3561
+ borderRadius: "8px",
3562
+ fontWeight: "600",
3563
+ display: "block"
3564
+ },
3565
+ states: {
3566
+ ":hover": { backgroundColor: "#1d4ed8" }
3567
+ }
3568
+ }
3569
+ }
3570
+ ]
3571
+ })
3572
+ },
3573
+ {
3574
+ id: "cta-banner",
3575
+ name: "CTA Banner",
3576
+ category: "cta",
3577
+ categoryLabel: "Call to Action",
3578
+ description: "High-contrast conversion banner with title and action button",
3579
+ icon: "layout",
3580
+ createNodeTree: (gen = defaultGenId) => ({
3581
+ id: gen("section"),
3582
+ type: "section",
3583
+ styles: {
3584
+ base: {
3585
+ padding: "60px 24px",
3586
+ backgroundColor: "#0f172a",
3587
+ color: "#ffffff",
3588
+ borderRadius: "16px",
3589
+ textAlign: "center",
3590
+ width: "100%"
3591
+ }
3592
+ },
3593
+ children: [
3594
+ {
3595
+ id: gen("heading"),
3596
+ type: "heading",
3597
+ props: { text: "Ready to boost your workflow?", level: 2 },
3598
+ styles: {
3599
+ base: { fontSize: "32px", fontWeight: "700", color: "#ffffff", marginBottom: "12px" }
3600
+ }
3601
+ },
3602
+ {
3603
+ id: gen("paragraph"),
3604
+ type: "paragraph",
3605
+ props: { content: "Start building with zero installation and instant live preview." },
3606
+ styles: {
3607
+ base: { fontSize: "16px", color: "#94a3b8", marginBottom: "24px", maxWidth: "600px", margin: "0 auto 24px auto" }
3608
+ }
3609
+ },
3610
+ {
3611
+ id: gen("button"),
3612
+ type: "button",
3613
+ props: { label: "Start Free Trial", href: "#signup" },
3614
+ styles: {
3615
+ base: {
3616
+ backgroundColor: "#ffffff",
3617
+ color: "#0f172a",
3618
+ padding: "12px 28px",
3619
+ borderRadius: "8px",
3620
+ fontWeight: "700",
3621
+ display: "inline-block"
3622
+ },
3623
+ states: {
3624
+ ":hover": { backgroundColor: "#f1f5f9" }
3625
+ }
3626
+ }
3627
+ }
3628
+ ]
3629
+ })
3630
+ },
3631
+ // --- Starter Form Templates (STORA-350) ---
3632
+ {
3633
+ id: "form-contact-us",
3634
+ name: "Contact Us Form",
3635
+ category: "forms",
3636
+ categoryLabel: "Form Templates",
3637
+ description: "Contact form with Name, Email, Subject, Message, and submit action pipeline with API request and toast notifications",
3638
+ icon: "form",
3639
+ createNodeTree: (gen = defaultGenId) => ({
3640
+ id: gen("section"),
3641
+ type: "section",
3642
+ styles: {
3643
+ base: {
3644
+ padding: "64px 20px",
3645
+ backgroundColor: "#f8fafc",
3646
+ width: "100%"
3647
+ }
3648
+ },
3649
+ children: [
3650
+ {
3651
+ id: gen("container"),
3652
+ type: "container",
3653
+ props: { tag: "div", maxWidth: "640px" },
3654
+ styles: {
3655
+ base: {
3656
+ maxWidth: "640px",
3657
+ margin: "0 auto",
3658
+ width: "100%",
3659
+ backgroundColor: "#ffffff",
3660
+ padding: "36px",
3661
+ borderRadius: "16px",
3662
+ boxShadow: "0 4px 6px -1px rgba(0, 0, 0, 0.05), 0 2px 4px -2px rgba(0, 0, 0, 0.05)",
3663
+ border: "1px solid #e2e8f0"
3664
+ }
3665
+ },
3666
+ children: [
3667
+ {
3668
+ id: gen("heading"),
3669
+ type: "heading",
3670
+ props: { text: "Contact Us", level: 2 },
3671
+ styles: {
3672
+ base: {
3673
+ fontSize: "28px",
3674
+ fontWeight: "700",
3675
+ color: "#0f172a",
3676
+ marginBottom: "8px",
3677
+ textAlign: "center"
3678
+ }
3679
+ }
3680
+ },
3681
+ {
3682
+ id: gen("paragraph"),
3683
+ type: "paragraph",
3684
+ props: {
3685
+ content: "Have questions or need assistance? Fill out the form below and we will get back to you shortly."
3686
+ },
3687
+ styles: {
3688
+ base: {
3689
+ fontSize: "15px",
3690
+ color: "#64748b",
3691
+ marginBottom: "28px",
3692
+ textAlign: "center",
3693
+ lineHeight: "1.5"
3694
+ }
3695
+ }
3696
+ },
3697
+ {
3698
+ id: gen("form"),
3699
+ type: "form",
3700
+ props: {
3701
+ name: "contact_us_form",
3702
+ method: "POST",
3703
+ preventDefault: true,
3704
+ scrollToFirstError: true,
3705
+ resetOnSubmit: true
3706
+ },
3707
+ styles: {
3708
+ base: {
3709
+ display: "flex",
3710
+ flexDirection: "column",
3711
+ gap: "20px",
3712
+ width: "100%"
3713
+ }
3714
+ },
3715
+ actions: [
3716
+ {
3717
+ id: gen("pipeline"),
3718
+ trigger: "submit",
3719
+ label: "Submit Contact Form",
3720
+ enabled: true,
3721
+ steps: [
3722
+ {
3723
+ id: gen("step"),
3724
+ type: "api_request",
3725
+ label: "Send Contact Message",
3726
+ payload: {
3727
+ url: "/api/mock/submit-lead",
3728
+ method: "POST",
3729
+ bodyFormat: "json"
3730
+ },
3731
+ onSuccess: [
3732
+ {
3733
+ id: gen("step"),
3734
+ type: "show_toast",
3735
+ label: "Show Success Toast",
3736
+ payload: {
3737
+ message: "Thank you! Your message has been sent successfully.",
3738
+ type: "success",
3739
+ title: "Message Sent",
3740
+ duration: 4e3
3741
+ }
3742
+ },
3743
+ {
3744
+ id: gen("step"),
3745
+ type: "reset_form",
3746
+ label: "Reset Form",
3747
+ payload: {}
3748
+ }
3749
+ ],
3750
+ onError: [
3751
+ {
3752
+ id: gen("step"),
3753
+ type: "show_toast",
3754
+ label: "Show Error Toast",
3755
+ payload: {
3756
+ message: "Failed to send message. Please check your connection and try again.",
3757
+ type: "error",
3758
+ title: "Submission Failed",
3759
+ duration: 5e3
3760
+ }
3761
+ }
3762
+ ]
3763
+ }
3764
+ ]
3765
+ }
3766
+ ],
3767
+ children: [
3768
+ {
3769
+ id: gen("input"),
3770
+ type: "input",
3771
+ props: {
3772
+ name: "name",
3773
+ label: "Your Name",
3774
+ type: "text",
3775
+ placeholder: "Jane Doe",
3776
+ required: true,
3777
+ rules: [
3778
+ { type: "required", message: "Please enter your name" },
3779
+ { type: "min_length", value: 2, message: "Name must be at least 2 characters" }
3780
+ ]
3781
+ },
3782
+ styles: {
3783
+ base: {
3784
+ width: "100%",
3785
+ padding: "10px 14px",
3786
+ borderRadius: "8px",
3787
+ border: "1px solid #cbd5e1",
3788
+ fontSize: "14px"
3789
+ }
3790
+ }
3791
+ },
3792
+ {
3793
+ id: gen("input"),
3794
+ type: "input",
3795
+ props: {
3796
+ name: "email",
3797
+ label: "Email Address",
3798
+ type: "email",
3799
+ placeholder: "jane@example.com",
3800
+ required: true,
3801
+ rules: [
3802
+ { type: "required", message: "Please enter your email" },
3803
+ { type: "email", message: "Please enter a valid email address" }
3804
+ ]
3805
+ },
3806
+ styles: {
3807
+ base: {
3808
+ width: "100%",
3809
+ padding: "10px 14px",
3810
+ borderRadius: "8px",
3811
+ border: "1px solid #cbd5e1",
3812
+ fontSize: "14px"
3813
+ }
3814
+ }
3815
+ },
3816
+ {
3817
+ id: gen("input"),
3818
+ type: "input",
3819
+ props: {
3820
+ name: "subject",
3821
+ label: "Subject",
3822
+ type: "text",
3823
+ placeholder: "How can we help you?",
3824
+ required: true,
3825
+ rules: [
3826
+ { type: "required", message: "Please enter a subject" }
3827
+ ]
3828
+ },
3829
+ styles: {
3830
+ base: {
3831
+ width: "100%",
3832
+ padding: "10px 14px",
3833
+ borderRadius: "8px",
3834
+ border: "1px solid #cbd5e1",
3835
+ fontSize: "14px"
3836
+ }
3837
+ }
3838
+ },
3839
+ {
3840
+ id: gen("textarea"),
3841
+ type: "textarea",
3842
+ props: {
3843
+ name: "message",
3844
+ label: "Message",
3845
+ placeholder: "Write your message here...",
3846
+ rows: 4,
3847
+ required: true,
3848
+ rules: [
3849
+ { type: "required", message: "Please enter your message" },
3850
+ { type: "min_length", value: 10, message: "Message must be at least 10 characters" }
3851
+ ]
3852
+ },
3853
+ styles: {
3854
+ base: {
3855
+ width: "100%",
3856
+ padding: "10px 14px",
3857
+ borderRadius: "8px",
3858
+ border: "1px solid #cbd5e1",
3859
+ fontSize: "14px"
3860
+ }
3861
+ }
3862
+ },
3863
+ {
3864
+ id: gen("button"),
3865
+ type: "button",
3866
+ props: {
3867
+ label: "Send Message",
3868
+ variant: "primary",
3869
+ buttonType: "submit"
3870
+ },
3871
+ styles: {
3872
+ base: {
3873
+ width: "100%",
3874
+ backgroundColor: "#2563eb",
3875
+ color: "#ffffff",
3876
+ padding: "12px",
3877
+ borderRadius: "8px",
3878
+ fontWeight: "600",
3879
+ fontSize: "15px",
3880
+ display: "inline-block",
3881
+ textAlign: "center"
3882
+ },
3883
+ states: {
3884
+ ":hover": { backgroundColor: "#1d4ed8" }
3885
+ }
3886
+ }
3887
+ }
3888
+ ]
3889
+ }
3890
+ ]
3891
+ }
3892
+ ]
3893
+ })
3894
+ },
3895
+ {
3896
+ id: "form-newsletter",
3897
+ name: "Newsletter Subscribe Form",
3898
+ category: "forms",
3899
+ categoryLabel: "Form Templates",
3900
+ description: "Inline email newsletter subscription form with real-time feedback",
3901
+ icon: "mail",
3902
+ createNodeTree: (gen = defaultGenId) => ({
3903
+ id: gen("section"),
3904
+ type: "section",
3905
+ styles: {
3906
+ base: {
3907
+ padding: "48px 20px",
3908
+ backgroundColor: "#f1f5f9",
3909
+ width: "100%"
3910
+ }
3911
+ },
3912
+ children: [
3913
+ {
3914
+ id: gen("container"),
3915
+ type: "container",
3916
+ props: { tag: "div", maxWidth: "580px" },
3917
+ styles: {
3918
+ base: {
3919
+ maxWidth: "580px",
3920
+ margin: "0 auto",
3921
+ width: "100%",
3922
+ textAlign: "center"
3923
+ }
3924
+ },
3925
+ children: [
3926
+ {
3927
+ id: gen("heading"),
3928
+ type: "heading",
3929
+ props: { text: "Stay in the Loop", level: 3 },
3930
+ styles: {
3931
+ base: {
3932
+ fontSize: "26px",
3933
+ fontWeight: "700",
3934
+ color: "#0f172a",
3935
+ marginBottom: "8px"
3936
+ }
3937
+ }
3938
+ },
3939
+ {
3940
+ id: gen("paragraph"),
3941
+ type: "paragraph",
3942
+ props: {
3943
+ content: "Subscribe to our newsletter for weekly curated insights, updates, and best practices."
3944
+ },
3945
+ styles: {
3946
+ base: {
3947
+ fontSize: "15px",
3948
+ color: "#64748b",
3949
+ marginBottom: "24px",
3950
+ lineHeight: "1.5"
3951
+ }
3952
+ }
3953
+ },
3954
+ {
3955
+ id: gen("form"),
3956
+ type: "form",
3957
+ props: {
3958
+ name: "newsletter_form",
3959
+ method: "POST",
3960
+ preventDefault: true,
3961
+ resetOnSubmit: true
3962
+ },
3963
+ styles: {
3964
+ base: {
3965
+ display: "flex",
3966
+ flexDirection: "row",
3967
+ gap: "8px",
3968
+ alignItems: "center",
3969
+ width: "100%"
3970
+ },
3971
+ mobile: {
3972
+ flexDirection: "column"
3973
+ }
3974
+ },
3975
+ actions: [
3976
+ {
3977
+ id: gen("pipeline"),
3978
+ trigger: "submit",
3979
+ label: "Subscribe to Newsletter",
3980
+ enabled: true,
3981
+ steps: [
3982
+ {
3983
+ id: gen("step"),
3984
+ type: "api_request",
3985
+ label: "Submit Subscription",
3986
+ payload: {
3987
+ url: "/api/mock/submit-lead",
3988
+ method: "POST",
3989
+ bodyFormat: "json"
3990
+ },
3991
+ onSuccess: [
3992
+ {
3993
+ id: gen("step"),
3994
+ type: "show_toast",
3995
+ label: "Show Success Toast",
3996
+ payload: {
3997
+ message: "Thank you for subscribing to our newsletter!",
3998
+ type: "success",
3999
+ title: "Subscription Confirmed",
4000
+ duration: 4e3
4001
+ }
4002
+ },
4003
+ {
4004
+ id: gen("step"),
4005
+ type: "reset_form",
4006
+ label: "Reset Form",
4007
+ payload: {}
4008
+ }
4009
+ ],
4010
+ onError: [
4011
+ {
4012
+ id: gen("step"),
4013
+ type: "show_toast",
4014
+ label: "Show Error Toast",
4015
+ payload: {
4016
+ message: "Unable to subscribe right now. Please try again later.",
4017
+ type: "error",
4018
+ title: "Error",
4019
+ duration: 5e3
4020
+ }
4021
+ }
4022
+ ]
4023
+ }
4024
+ ]
4025
+ }
4026
+ ],
4027
+ children: [
4028
+ {
4029
+ id: gen("input"),
4030
+ type: "input",
4031
+ props: {
4032
+ name: "email",
4033
+ type: "email",
4034
+ placeholder: "Enter your email address...",
4035
+ required: true,
4036
+ rules: [
4037
+ { type: "required", message: "Email address is required" },
4038
+ { type: "email", message: "Please enter a valid email address" }
4039
+ ]
4040
+ },
4041
+ styles: {
4042
+ base: {
4043
+ flex: "1 1 0%",
4044
+ minWidth: "0",
4045
+ padding: "12px 16px",
4046
+ borderRadius: "8px",
4047
+ border: "1px solid #cbd5e1",
4048
+ backgroundColor: "#ffffff",
4049
+ fontSize: "14px"
4050
+ }
4051
+ }
4052
+ },
4053
+ {
4054
+ id: gen("button"),
4055
+ type: "button",
4056
+ props: {
4057
+ label: "Subscribe",
4058
+ variant: "primary",
4059
+ buttonType: "submit"
4060
+ },
4061
+ styles: {
4062
+ base: {
4063
+ backgroundColor: "#2563eb",
4064
+ color: "#ffffff",
4065
+ padding: "12px 24px",
4066
+ borderRadius: "8px",
4067
+ fontWeight: "600",
4068
+ fontSize: "14px",
4069
+ whiteSpace: "nowrap"
4070
+ },
4071
+ states: {
4072
+ ":hover": { backgroundColor: "#1d4ed8" }
4073
+ }
4074
+ }
4075
+ }
4076
+ ]
4077
+ }
4078
+ ]
4079
+ }
4080
+ ]
4081
+ })
4082
+ },
4083
+ {
4084
+ id: "form-lead-gen",
4085
+ name: "Lead Generation Form",
4086
+ category: "forms",
4087
+ categoryLabel: "Form Templates",
4088
+ description: "Multi-field lead generation form with phone validation, interest dropdown, and API submission pipeline",
4089
+ icon: "users",
4090
+ createNodeTree: (gen = defaultGenId) => ({
4091
+ id: gen("section"),
4092
+ type: "section",
4093
+ styles: {
4094
+ base: {
4095
+ padding: "64px 20px",
4096
+ backgroundColor: "#ffffff",
4097
+ width: "100%"
4098
+ }
4099
+ },
4100
+ children: [
4101
+ {
4102
+ id: gen("container"),
4103
+ type: "container",
4104
+ props: { tag: "div", maxWidth: "640px" },
4105
+ styles: {
4106
+ base: {
4107
+ maxWidth: "640px",
4108
+ margin: "0 auto",
4109
+ width: "100%",
4110
+ backgroundColor: "#ffffff",
4111
+ padding: "36px",
4112
+ borderRadius: "16px",
4113
+ border: "1px solid #e2e8f0",
4114
+ boxShadow: "0 10px 25px -5px rgba(0, 0, 0, 0.05)"
4115
+ }
4116
+ },
4117
+ children: [
4118
+ {
4119
+ id: gen("badge"),
4120
+ type: "badge",
4121
+ props: { label: "FREE CONSULTATION", variant: "primary" },
4122
+ styles: { base: { marginBottom: "12px", display: "inline-block" } }
4123
+ },
4124
+ {
4125
+ id: gen("heading"),
4126
+ type: "heading",
4127
+ props: { text: "Schedule a Consultation", level: 2 },
4128
+ styles: {
4129
+ base: {
4130
+ fontSize: "28px",
4131
+ fontWeight: "700",
4132
+ color: "#0f172a",
4133
+ marginBottom: "8px"
4134
+ }
4135
+ }
4136
+ },
4137
+ {
4138
+ id: gen("paragraph"),
4139
+ type: "paragraph",
4140
+ props: {
4141
+ content: "Share your project details with our solutions team. We will analyze your needs and provide a personalized roadmap."
4142
+ },
4143
+ styles: {
4144
+ base: {
4145
+ fontSize: "15px",
4146
+ color: "#64748b",
4147
+ marginBottom: "28px",
4148
+ lineHeight: "1.5"
4149
+ }
4150
+ }
4151
+ },
4152
+ {
4153
+ id: gen("form"),
4154
+ type: "form",
4155
+ props: {
4156
+ name: "lead_generation_form",
4157
+ method: "POST",
4158
+ preventDefault: true,
4159
+ scrollToFirstError: true,
4160
+ resetOnSubmit: true
4161
+ },
4162
+ styles: {
4163
+ base: {
4164
+ display: "flex",
4165
+ flexDirection: "column",
4166
+ gap: "18px",
4167
+ width: "100%"
4168
+ }
4169
+ },
4170
+ actions: [
4171
+ {
4172
+ id: gen("pipeline"),
4173
+ trigger: "submit",
4174
+ label: "Submit Lead Form",
4175
+ enabled: true,
4176
+ steps: [
4177
+ {
4178
+ id: gen("step"),
4179
+ type: "api_request",
4180
+ label: "Send Lead Data",
4181
+ payload: {
4182
+ url: "/api/mock/submit-lead",
4183
+ method: "POST",
4184
+ bodyFormat: "json"
4185
+ },
4186
+ onSuccess: [
4187
+ {
4188
+ id: gen("step"),
4189
+ type: "show_toast",
4190
+ label: "Show Success Toast",
4191
+ payload: {
4192
+ message: "Thank you! Your request has been received. Our team will contact you shortly.",
4193
+ type: "success",
4194
+ title: "Request Submitted",
4195
+ duration: 4e3
4196
+ }
4197
+ },
4198
+ {
4199
+ id: gen("step"),
4200
+ type: "reset_form",
4201
+ label: "Reset Form",
4202
+ payload: {}
4203
+ }
4204
+ ],
4205
+ onError: [
4206
+ {
4207
+ id: gen("step"),
4208
+ type: "show_toast",
4209
+ label: "Show Error Toast",
4210
+ payload: {
4211
+ message: "Submission failed. Please verify your information and try again.",
4212
+ type: "error",
4213
+ title: "Submission Error",
4214
+ duration: 5e3
4215
+ }
4216
+ }
4217
+ ]
4218
+ }
4219
+ ]
4220
+ }
4221
+ ],
4222
+ children: [
4223
+ {
4224
+ id: gen("input"),
4225
+ type: "input",
4226
+ props: {
4227
+ name: "full_name",
4228
+ label: "Full Name",
4229
+ type: "text",
4230
+ placeholder: "Alex Morgan",
4231
+ required: true,
4232
+ rules: [
4233
+ { type: "required", message: "Full name is required" },
4234
+ { type: "min_length", value: 2, message: "Name must be at least 2 characters" }
4235
+ ]
4236
+ },
4237
+ styles: {
4238
+ base: {
4239
+ width: "100%",
4240
+ padding: "10px 14px",
4241
+ borderRadius: "8px",
4242
+ border: "1px solid #cbd5e1",
4243
+ fontSize: "14px"
4244
+ }
4245
+ }
4246
+ },
4247
+ {
4248
+ id: gen("input"),
4249
+ type: "input",
4250
+ props: {
4251
+ name: "email",
4252
+ label: "Business Email",
4253
+ type: "email",
4254
+ placeholder: "alex@company.com",
4255
+ required: true,
4256
+ rules: [
4257
+ { type: "required", message: "Business email is required" },
4258
+ { type: "email", message: "Please enter a valid email address" }
4259
+ ]
4260
+ },
4261
+ styles: {
4262
+ base: {
4263
+ width: "100%",
4264
+ padding: "10px 14px",
4265
+ borderRadius: "8px",
4266
+ border: "1px solid #cbd5e1",
4267
+ fontSize: "14px"
4268
+ }
4269
+ }
4270
+ },
4271
+ {
4272
+ id: gen("input"),
4273
+ type: "input",
4274
+ props: {
4275
+ name: "phone",
4276
+ label: "Phone Number",
4277
+ type: "tel",
4278
+ placeholder: "+62 812-3456-7890",
4279
+ required: true,
4280
+ rules: [
4281
+ { type: "required", message: "Phone number is required" },
4282
+ {
4283
+ type: "custom_regex",
4284
+ value: "^[+]?[0-9\\s-()]{8,20}$",
4285
+ message: "Please enter a valid phone number (min 8 digits)"
4286
+ }
4287
+ ]
4288
+ },
4289
+ styles: {
4290
+ base: {
4291
+ width: "100%",
4292
+ padding: "10px 14px",
4293
+ borderRadius: "8px",
4294
+ border: "1px solid #cbd5e1",
4295
+ fontSize: "14px"
4296
+ }
4297
+ }
4298
+ },
4299
+ {
4300
+ id: gen("select"),
4301
+ type: "select",
4302
+ props: {
4303
+ name: "interest",
4304
+ label: "Area of Interest",
4305
+ placeholder: "Select your interest / service...",
4306
+ required: true,
4307
+ defaultValue: "",
4308
+ options: [
4309
+ { label: "Web Platform Development", value: "web_platform" },
4310
+ { label: "Mobile Application", value: "mobile_app" },
4311
+ { label: "Cloud Architecture & DevOps", value: "cloud_devops" },
4312
+ { label: "UI/UX Product Design", value: "product_design" },
4313
+ { label: "General Inquiry", value: "general" }
4314
+ ],
4315
+ rules: [
4316
+ { type: "required", message: "Please select an area of interest" }
4317
+ ]
4318
+ },
4319
+ styles: {
4320
+ base: {
4321
+ width: "100%",
4322
+ padding: "10px 14px",
4323
+ borderRadius: "8px",
4324
+ border: "1px solid #cbd5e1",
4325
+ fontSize: "14px",
4326
+ backgroundColor: "#ffffff"
4327
+ }
4328
+ }
4329
+ },
4330
+ {
4331
+ id: gen("input"),
4332
+ type: "input",
4333
+ props: {
4334
+ name: "company",
4335
+ label: "Company Name (Optional)",
4336
+ type: "text",
4337
+ placeholder: "Company / Organization"
4338
+ },
4339
+ styles: {
4340
+ base: {
4341
+ width: "100%",
4342
+ padding: "10px 14px",
4343
+ borderRadius: "8px",
4344
+ border: "1px solid #cbd5e1",
4345
+ fontSize: "14px"
4346
+ }
4347
+ }
4348
+ },
4349
+ {
4350
+ id: gen("button"),
4351
+ type: "button",
4352
+ props: {
4353
+ label: "Request Consultation",
4354
+ variant: "primary",
4355
+ buttonType: "submit"
4356
+ },
4357
+ styles: {
4358
+ base: {
4359
+ width: "100%",
4360
+ backgroundColor: "#2563eb",
4361
+ color: "#ffffff",
4362
+ padding: "12px 24px",
4363
+ borderRadius: "8px",
4364
+ fontWeight: "600",
4365
+ fontSize: "15px",
4366
+ marginTop: "4px"
4367
+ },
4368
+ states: {
4369
+ ":hover": { backgroundColor: "#1d4ed8" }
4370
+ }
4371
+ }
4372
+ }
4373
+ ]
4374
+ }
4375
+ ]
4376
+ }
4377
+ ]
4378
+ })
4379
+ }
4380
+ ];
2271
4381
  export {
2272
4382
  ComponentRegistry,
4383
+ STARTER_BLOCKS,
2273
4384
  TRAIT_GROUP_LABELS,
2274
4385
  TRAIT_GROUP_ORDER,
4386
+ acceptTrait,
2275
4387
  actionTrait,
2276
4388
  altTrait,
2277
4389
  ariaLabelTrait,
2278
4390
  autoCompleteTrait,
4391
+ autoDisableOnSubmitTrait,
4392
+ autoGrowTrait,
2279
4393
  autoplayTrait,
2280
4394
  badgeDefinition,
2281
4395
  blockquoteDefinition,
2282
4396
  buttonDefinition,
4397
+ buttonSubmitDefinition,
2283
4398
  buttonTypeTrait,
2284
4399
  checkboxDefinition,
2285
4400
  citeTrait,
@@ -2293,42 +4408,68 @@ export {
2293
4408
  coreComponentDefinitions,
2294
4409
  createDefaultComponentRegistry,
2295
4410
  defaultCheckedTrait,
4411
+ defaultSelectedTrait,
2296
4412
  defaultValueTrait,
2297
4413
  disabledTrait,
2298
4414
  extractComponentRequirements,
2299
4415
  fieldNameTrait,
4416
+ fileUploadDefinition,
2300
4417
  formDefinition,
2301
4418
  headingDefinition,
4419
+ helperTextTrait,
2302
4420
  hrefTrait,
2303
4421
  htmlEmbedDefinition,
2304
4422
  iconDefinition,
2305
4423
  idTrait,
2306
4424
  imageDefinition,
4425
+ indeterminateTrait,
2307
4426
  inputDefinition,
2308
4427
  inputTypeTrait,
2309
4428
  isBindableField,
4429
+ labelTextTrait,
2310
4430
  linkDefinition,
2311
4431
  listDefinition,
2312
4432
  listItemDefinition,
4433
+ loadingTextTrait,
2313
4434
  loadingTrait,
2314
4435
  loopTrait,
4436
+ maxCharCountTrait,
4437
+ maxFileSizeTrait,
4438
+ maxLengthTrait,
2315
4439
  methodTrait,
4440
+ minLengthTrait,
4441
+ multipleTrait,
2316
4442
  mutedTrait,
4443
+ optionsListTrait,
4444
+ orientationTrait,
2317
4445
  pageDefinition,
2318
4446
  paragraphDefinition,
4447
+ patternTrait,
2319
4448
  placeholderTrait,
2320
4449
  posterTrait,
4450
+ prefixIconTrait,
4451
+ preventDefaultTrait,
2321
4452
  primitiveTypeForField,
2322
4453
  radioDefinition,
4454
+ radioGroupDefinition,
4455
+ radioItemDefinition,
2323
4456
  readOnlyTrait,
2324
4457
  relTrait,
2325
4458
  requiredTrait,
4459
+ resetOnSubmitTrait,
4460
+ resizeTrait,
2326
4461
  rowSpanTrait,
2327
4462
  rowsTrait,
4463
+ scrollToFirstErrorTrait,
2328
4464
  sectionDefinition,
2329
4465
  selectDefinition,
4466
+ showPreviewTrait,
4467
+ showSpinnerTrait,
2330
4468
  sortTraits,
2331
4469
  srcTrait,
4470
+ suffixIconTrait,
4471
+ switchDefinition,
4472
+ switchSizeTrait,
2332
4473
  tableCellDefinition,
2333
4474
  tableDefinition,
2334
4475
  tableRowDefinition,