@siliconst/metaui 1.4.37 → 1.4.51

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.
Files changed (62) hide show
  1. package/package.json +1 -1
  2. package/src/nz/co/siliconst/ui5/metaui/controls/DynamicHost-dbg.js +24 -0
  3. package/src/nz/co/siliconst/ui5/metaui/controls/DynamicHost-dbg.js.map +1 -1
  4. package/src/nz/co/siliconst/ui5/metaui/controls/DynamicHost.d.ts +24 -0
  5. package/src/nz/co/siliconst/ui5/metaui/controls/DynamicHost.d.ts.map +1 -1
  6. package/src/nz/co/siliconst/ui5/metaui/controls/DynamicHost.js +1 -1
  7. package/src/nz/co/siliconst/ui5/metaui/controls/DynamicHost.js.map +1 -1
  8. package/src/nz/co/siliconst/ui5/metaui/controls/DynamicHost.ts +15 -1
  9. package/src/nz/co/siliconst/ui5/metaui/controls/host/GeneratorHost-dbg.js +34 -0
  10. package/src/nz/co/siliconst/ui5/metaui/controls/host/GeneratorHost-dbg.js.map +1 -1
  11. package/src/nz/co/siliconst/ui5/metaui/controls/host/GeneratorHost.d.ts +34 -0
  12. package/src/nz/co/siliconst/ui5/metaui/controls/host/GeneratorHost.d.ts.map +1 -1
  13. package/src/nz/co/siliconst/ui5/metaui/controls/host/GeneratorHost.js +1 -1
  14. package/src/nz/co/siliconst/ui5/metaui/controls/host/GeneratorHost.js.map +1 -1
  15. package/src/nz/co/siliconst/ui5/metaui/controls/host/GeneratorHost.ts +25 -1
  16. package/src/nz/co/siliconst/ui5/metaui/core/Engine-dbg.js +31 -1
  17. package/src/nz/co/siliconst/ui5/metaui/core/Engine-dbg.js.map +1 -1
  18. package/src/nz/co/siliconst/ui5/metaui/core/Engine.d.ts +2 -0
  19. package/src/nz/co/siliconst/ui5/metaui/core/Engine.d.ts.map +1 -1
  20. package/src/nz/co/siliconst/ui5/metaui/core/Engine.js +1 -1
  21. package/src/nz/co/siliconst/ui5/metaui/core/Engine.js.map +1 -1
  22. package/src/nz/co/siliconst/ui5/metaui/core/Engine.ts +38 -0
  23. package/src/nz/co/siliconst/ui5/metaui/core/PolicyEngine-dbg.js +15 -96
  24. package/src/nz/co/siliconst/ui5/metaui/core/PolicyEngine-dbg.js.map +1 -1
  25. package/src/nz/co/siliconst/ui5/metaui/core/PolicyEngine.d.ts +1 -6
  26. package/src/nz/co/siliconst/ui5/metaui/core/PolicyEngine.d.ts.map +1 -1
  27. package/src/nz/co/siliconst/ui5/metaui/core/PolicyEngine.js +1 -1
  28. package/src/nz/co/siliconst/ui5/metaui/core/PolicyEngine.js.map +1 -1
  29. package/src/nz/co/siliconst/ui5/metaui/core/PolicyEngine.ts +20 -100
  30. package/src/nz/co/siliconst/ui5/metaui/core/StateManager-dbg.js.map +1 -1
  31. package/src/nz/co/siliconst/ui5/metaui/core/StateManager.js.map +1 -1
  32. package/src/nz/co/siliconst/ui5/metaui/core/StateManager.ts +1 -1
  33. package/src/nz/co/siliconst/ui5/metaui/interfaces/IPlugin-dbg.js.map +1 -1
  34. package/src/nz/co/siliconst/ui5/metaui/interfaces/IPlugin.d.ts +1 -0
  35. package/src/nz/co/siliconst/ui5/metaui/interfaces/IPlugin.d.ts.map +1 -1
  36. package/src/nz/co/siliconst/ui5/metaui/interfaces/IPlugin.ts +1 -0
  37. package/src/nz/co/siliconst/ui5/metaui/interfaces/ISchema-dbg.js.map +1 -1
  38. package/src/nz/co/siliconst/ui5/metaui/interfaces/ISchema.d.ts +2 -1
  39. package/src/nz/co/siliconst/ui5/metaui/interfaces/ISchema.d.ts.map +1 -1
  40. package/src/nz/co/siliconst/ui5/metaui/interfaces/ISchema.ts +2 -1
  41. package/src/nz/co/siliconst/ui5/metaui/layouts/WizardLayout-dbg.js +327 -67
  42. package/src/nz/co/siliconst/ui5/metaui/layouts/WizardLayout-dbg.js.map +1 -1
  43. package/src/nz/co/siliconst/ui5/metaui/layouts/WizardLayout.d.ts +57 -15
  44. package/src/nz/co/siliconst/ui5/metaui/layouts/WizardLayout.d.ts.map +1 -1
  45. package/src/nz/co/siliconst/ui5/metaui/layouts/WizardLayout.js +1 -1
  46. package/src/nz/co/siliconst/ui5/metaui/layouts/WizardLayout.js.map +1 -1
  47. package/src/nz/co/siliconst/ui5/metaui/layouts/WizardLayout.ts +375 -65
  48. package/src/nz/co/siliconst/ui5/metaui/library-preload.js +7 -7
  49. package/src/nz/co/siliconst/ui5/metaui/library-preload.js.map +1 -1
  50. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/BasePlugin-dbg.js +10 -15
  51. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/BasePlugin-dbg.js.map +1 -1
  52. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/BasePlugin.d.ts +4 -0
  53. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/BasePlugin.d.ts.map +1 -1
  54. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/BasePlugin.js +1 -1
  55. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/BasePlugin.js.map +1 -1
  56. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/BasePlugin.ts +10 -15
  57. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/StepInputPlugin-dbg.js +11 -1
  58. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/StepInputPlugin-dbg.js.map +1 -1
  59. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/StepInputPlugin.d.ts.map +1 -1
  60. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/StepInputPlugin.js +1 -1
  61. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/StepInputPlugin.js.map +1 -1
  62. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/StepInputPlugin.ts +10 -1
@@ -4,31 +4,73 @@ declare module "nz/co/siliconst/ui5/metaui/layouts/WizardLayout" {
4
4
  import { Engine } from "nz/co/siliconst/ui5/metaui/core/Engine";
5
5
  import Control from "sap/ui/core/Control";
6
6
  /**
7
- * Layout Manager responsible for generating a responsive SAP Fiori Wizard.
8
- * It segments the schema fields into discrete Wizard Steps based on `uiLayout` elements
9
- * of type `Group` or `WizardStep`.
7
+ * Minimal structural contract for accessing the hosting GeneratorHost without importing
8
+ * it directly (which would create a circular dependency between WizardLayout ↔ GeneratorHost).
9
+ */
10
+ interface IWizardCapableHost {
11
+ /** Returns the active StateManager. Used to extract a payload snapshot at step-change time. */
12
+ getStateManager(): {
13
+ extractPayload(): Record<string, unknown>;
14
+ } | null;
15
+ /** Fires a UI5 event upward on the host control. */
16
+ fireEvent(eventName: string, params: Record<string, unknown>): void;
17
+ }
18
+ /**
19
+ * Layout Manager that generates a custom paginated step navigator.
20
+ * Renders exactly one step at a time, validates current-step fields before advancing,
21
+ * and fires `beforeLayoutSectionChange` with a full async API before each step transition.
10
22
  *
11
23
  * @namespace nz.co.siliconst.ui5.metaui.layouts
12
24
  * @public
13
25
  */
14
26
  export class WizardLayout implements ILayoutManager {
15
27
  /**
16
- * Renders the JSON Schema properties into a paginated UI5 Wizard using uiLayout.
28
+ * Renders the wizard as a custom step-by-step navigator.
17
29
  *
18
- * @param schema The active JSON schema object.
19
- * @param modelName The bound UI5 model name.
20
- * @param engine The central orchestrator for delegating plugin generation.
21
- * @param onSubmit Hook executed when the Wizard's native 'complete' event is fired.
22
- * @returns {Control} The generated sap.m.Wizard control.
30
+ * @param schema The active JSON schema object containing `uiLayout` step groups.
31
+ * @param modelName The bound UI5 model name for data bindings.
32
+ * @param engine The central Engine orchestrator for field generation and validation.
33
+ * @param onSubmit Hook executed when the user completes the final step successfully.
34
+ * @returns {Control} A VBox root container comprising the step header, content, and navigation.
23
35
  */
24
36
  render(schema: ISchema, modelName: string, engine: Engine, onSubmit?: () => void): Control;
25
37
  /**
26
- * Synthesizes a field into the wizard step form.
27
- * @param form The SimpleForm belonging to the step.
28
- * @param element The layout element definition.
29
- * @param schema The schema reference.
30
- * @param modelName The UI5 data model name.
31
- * @param engine The core Engine instance.
38
+ * Validates all fields registered during a specific step's form build.
39
+ *
40
+ * Routes error painting through `engine.reportSchemaError()` → `resolveVisualState()`
41
+ * → `plugin.setVisualValidationState()`. This is the single authoritative path for
42
+ * painting red borders in MetaUI, and correctly handles both default and
43
+ * `useMessageManager` modes.
44
+ *
45
+ * @param fieldPaths The list of binding paths collected during the step's form build.
46
+ * @param engine The Engine instance that holds the plugin registry and validation ledger.
47
+ * @returns {boolean} True if all fields are valid, false if any failed.
48
+ */
49
+ private _validateStep;
50
+ /**
51
+ * Constructs a SimpleForm for a single wizard step, recursively rendering all
52
+ * child layout elements and collecting their binding paths into `fieldPaths`.
53
+ *
54
+ * @param stepElement The top-level Group/WizardStep layout element for this step.
55
+ * @param schema The active JSON schema.
56
+ * @param modelName The UI5 JSONModel alias for data binding.
57
+ * @param engine The Engine instance for field generation.
58
+ * @param fieldPaths Collector array — all binding paths generated for this step are pushed here.
59
+ * @returns {SimpleForm} The assembled SimpleForm for this wizard step.
60
+ */
61
+ private _buildStepForm;
62
+ /**
63
+ * Recursively renders a single layout element into a SimpleForm.
64
+ * For `Group` elements, adds a Title and recurses into children.
65
+ * For `Control` elements, resolves the schema scope, generates the plugin control,
66
+ * and pushes the binding path to `fieldPaths` for per-step validation tracking.
67
+ *
68
+ * @param form The target SimpleForm to append content to.
69
+ * @param element The layout element to render.
70
+ * @param schema The active JSON schema.
71
+ * @param modelName The UI5 JSONModel alias for data binding.
72
+ * @param engine The Engine instance for field generation.
73
+ * @param fieldPaths Collector array for binding path tracking.
32
74
  */
33
75
  private _renderElementInForm;
34
76
  }
@@ -1 +1 @@
1
- {"version":3,"file":"WizardLayout.d.ts","sourceRoot":"../../../../../../../..","sources":["src/nz/co/siliconst/ui5/metaui/layouts/WizardLayout.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,iDAAiD,CAAC;IAWjE,OAAO,EAAqB,OAAO,EAAkB,MAAM,+CAA+C,CAAC;IAC3G,OAAO,EAAE,cAAc,EAAE,MAAM,sDAAsD,CAAC;IACtF,OAAO,EAAE,MAAM,EAAE,MAAM,wCAAwC,CAAC;IAGhE,OAAO,OAAO,MAAM,qBAAqB,CAAC;IAE1C;;;;;;;OAOG;IACH,MAAa,YAAa,YAAW,cAAc;QAC/C;;;;;;;;WAQG;QACI,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO;QA+CjG;;;;;;;WAOG;QACH,OAAO,CAAC,oBAAoB;KA4C/B;CAEA"}
1
+ {"version":3,"file":"WizardLayout.d.ts","sourceRoot":"../../../../../../../..","sources":["src/nz/co/siliconst/ui5/metaui/layouts/WizardLayout.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,iDAAiD,CAAC;IAyBjE,OAAO,EAAqB,OAAO,EAAkB,MAAM,+CAA+C,CAAC;IAE3G,OAAO,EAAE,cAAc,EAAE,MAAM,sDAAsD,CAAC;IACtF,OAAO,EAAE,MAAM,EAAE,MAAM,wCAAwC,CAAC;IAGhE,OAAO,OAAO,MAAM,qBAAqB,CAAC;IAE1C;;;OAGG;IACH,UAAU,kBAAkB;QACxB,+FAA+F;QAC/F,eAAe,IAAI;YAAE,cAAc,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;SAAE,GAAG,IAAI,CAAC;QACxE,oDAAoD;QACpD,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;KACvE;IAED;;;;;;;OAOG;IACH,MAAa,YAAa,YAAW,cAAc;QAC/C;;;;;;;;WAQG;QACI,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO;QAiOjG;;;;;;;;;;;WAWG;QACH,OAAO,CAAC,aAAa;QAwBrB;;;;;;;;;;WAUG;QACH,OAAO,CAAC,cAAc;QA0BtB;;;;;;;;;;;;WAYG;QACH,OAAO,CAAC,oBAAoB;KAwE/B;CAEA"}
@@ -1,2 +1,2 @@
1
- sap.ui.define(["sap/m/Wizard","sap/m/WizardStep","sap/ui/layout/form/SimpleForm","sap/m/Label","../core/SchemaNormalizer","../utils/Logger"],function(e,t,a,r,n,i){"use strict";const o=n["SchemaNormalizer"];const s=i["Logger"];class l{render(r,n,i,o){const l=new e({renderMode:"Page",showNextButton:true,complete:function(){if(o)o()}});if(!r.uiLayout||!Array.isArray(r.uiLayout)){s.warn("[MetaUI] Missing 'uiLayout' array in wizard schema. Wizard will not render any steps.");return l}r.uiLayout.forEach(e=>{if(e.type==="Group"||e.type==="WizardStep"){const o=new t({title:e.label||"Step",validated:true});const s=new a({editable:true,layout:"ResponsiveGridLayout",labelSpanXL:4,labelSpanL:4,labelSpanM:4,labelSpanS:12,adjustLabelSpan:false,emptySpanXL:0,emptySpanL:0,emptySpanM:0,emptySpanS:0,columnsXL:1,columnsL:1,columnsM:1,singleContainerFullSize:false});if(e.elements&&Array.isArray(e.elements)){e.elements.forEach(e=>{this._renderElementInForm(s,e,r,n,i)})}o.addContent(s);l.addStep(o)}else{s.warn(`[MetaUI] Top-level element '${e.type}' inside WizardLayout must be 'Group' or 'WizardStep'.`,"","WizardLayout")}});return l}_renderElementInForm(e,t,a,n,i){if(t.type==="Control"){if(!t.scope||!t.scope.startsWith("#/properties/")){s.error(`[MetaUI] Invalid scope '${t.scope}' in uiLayout Control.`,"","WizardLayout");return}const{meta:l,bindingPath:u,propKey:d}=o.resolveScope(a,t.scope);if(!l){s.error(`[MetaUI] Property '${d}' not found in schema definitions.`,"","WizardLayout");return}try{const a=t.label||l.ui?.label||d;const o=new r({text:a,required:l.required});const s={...l};if(t.widget){s.ui={...l.ui,widget:t.widget}}const p=i.generateField(s,`/${u}`,n);if(s.ui?.fullWidth){sap.ui.require(["sap/ui/layout/GridData"],e=>{p.setLayoutData(new e({span:"XL12 L12 M12 S12"}))})}e.addContent(o);e.addContent(p)}catch(t){s.error(`[MetaUI] Failed to render Wizard field ${d}`,t.message,"WizardLayout");e.addContent(new r({text:d}))}}else{s.warn(`[MetaUI] Nested groups within Wizard steps are not fully supported in SimpleForm yet.`,"","WizardLayout")}}}var u={__esModule:true};u.WizardLayout=l;return u});
1
+ sap.ui.define(["sap/ui/layout/form/SimpleForm","sap/m/Label","sap/m/VBox","sap/m/HBox","sap/m/Button","sap/m/ProgressIndicator","sap/m/Title","sap/ui/core/Title","sap/m/Text","../core/SchemaNormalizer","../utils/Logger"],function(e,t,a,r,n,i,o,s,l,u,d){"use strict";const p=u["SchemaNormalizer"];const c=d["Logger"];class m{render(e,t,s,u){if(!e.uiLayout||!Array.isArray(e.uiLayout)){c.warn("[MetaUI WizardLayout] Missing 'uiLayout' array in schema. Cannot build step navigator.","","WizardLayout");return new a}const d=e.uiLayout.filter(e=>e.type==="Group"||e.type==="WizardStep");if(d.length===0){c.warn("[MetaUI WizardLayout] No Group or WizardStep elements found in uiLayout.","","WizardLayout");return new a}const p=d.length;const m=[];const y=[];d.forEach(a=>{const r=[];const n=this._buildStepForm(a,e,t,s,r);m.push(n);y.push(r)});let f=0;const S=new o({level:"H3"});const g=new l;const h=new i({showValue:false,state:"None",height:"0.5rem"}).addStyleClass("metaUIWizardProgress");const L=new a({width:"100%"}).addStyleClass("metaUIWizardContent");const w=new n({text:"Previous",icon:"sap-icon://navigation-left-arrow",enabled:false,press:()=>W(f-1)});const z=new n({type:"Emphasized",text:p===1?"Complete":"Next Step",icon:"sap-icon://navigation-right-arrow",iconFirst:false,press:()=>I()});const W=e=>{if(e<0||e>=p){c.error("[MetaUI WizardLayout]",`Invalid navigation target: step ${e}`,"WizardLayout");return}f=e;const t=d[f];const a=f===p-1;S.setText(t.label||`Step ${f+1}`);g.setText(`Step ${f+1} of ${p}`);h.setPercentValue((f+1)/p*100);L.removeAllItems();L.addItem(m[f]);w.setEnabled(f>0);z.setText(a?"Complete":"Next Step");z.setIcon(a?"sap-icon://accept":"sap-icon://navigation-right-arrow")};const I=()=>{if(!this._validateStep(y[f],s)){c.debug("[MetaUI WizardLayout]",`Step ${f} failed local validation. Blocking navigation.`,"WizardLayout");return}if(f===p-1){if(u)u();return}const e=s.host;if(!e){W(f+1);return}const t=e.getStateManager();const a=t?t.extractPayload():{};let r=false;let n=false;const i=()=>{if(!n){n=true;W(f+1)}};e.fireEvent("beforeLayoutSectionChange",{stepIndex:f,payload:a,preventDefault:()=>{r=true},addError:(e,t)=>{r=true;const a=s.getPluginByPath(e);if(a&&typeof a.setVisualValidationState==="function"){a.setVisualValidationState(false,t)}},resumeNavigation:()=>{i()}});if(!r){i()}};W(0);const v=new r({width:"100%",justifyContent:"SpaceBetween",alignItems:"Center",items:[w,z]}).addStyleClass("sapUiSmallMarginTop");const b=new a({width:"100%",items:[new r({justifyContent:"SpaceBetween",alignItems:"Center",width:"100%",items:[S,g]}),h]}).addStyleClass("sapUiSmallMarginBottom");return new a({width:"100%",items:[b,L,v]})}_validateStep(e,t){let a=true;for(const r of e){const e=t.getPluginByPath(r);if(!e)continue;const n=e.validate();if(!n.isValid){t.reportSchemaError(r,n.errorMessage||"This field is required.");a=false}else{t.reportSchemaError(r,null)}}return a}_buildStepForm(t,a,r,n,i){const o=new e({editable:true,layout:"ResponsiveGridLayout",labelSpanXL:4,labelSpanL:4,labelSpanM:4,labelSpanS:12,adjustLabelSpan:false,emptySpanXL:0,emptySpanL:0,emptySpanM:0,emptySpanS:0,columnsXL:1,columnsL:1,columnsM:1,singleContainerFullSize:false});if(t.elements&&Array.isArray(t.elements)){t.elements.forEach(e=>{this._renderElementInForm(o,e,a,r,n,i)})}return o}_renderElementInForm(e,a,r,n,i,o){if(a.type==="Group"){if(a.label){e.addContent(new s({text:a.label}))}if(a.elements&&Array.isArray(a.elements)){a.elements.forEach(t=>{this._renderElementInForm(e,t,r,n,i,o)})}return}if(a.type==="Control"){if(!a.scope||!a.scope.startsWith("#/properties/")){c.error(`[MetaUI WizardLayout] Invalid scope '${a.scope}' — must start with '#/properties/'.`,"","WizardLayout");return}const{meta:s,bindingPath:l,propKey:u}=p.resolveScope(r,a.scope);if(!s){c.error(`[MetaUI WizardLayout] Property '${u}' not found in schema.`,"","WizardLayout");return}try{const r=a.label||s.ui?.label||u;const d=new t({text:r,required:s.required===true});const p={...s};if(a.widget){p.ui={...s.ui||{},widget:a.widget}}const c=`/${l}`;const m=i.generateField(p,c,n);o.push(c);if(p.ui?.fullWidth){sap.ui.require(["sap/ui/layout/GridData"],e=>{m.setLayoutData(new e({span:"XL12 L12 M12 S12"}))})}e.addContent(d);e.addContent(m)}catch(a){c.error(`[MetaUI WizardLayout] Failed to render field '${u}'`,a.message,"WizardLayout");e.addContent(new t({text:u}))}return}c.warn(`[MetaUI WizardLayout] Unsupported element type '${a.type}' inside a wizard step.`,"","WizardLayout")}}var y={__esModule:true};y.WizardLayout=m;return y});
2
2
  //# sourceMappingURL=WizardLayout.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"WizardLayout.js","names":["SchemaNormalizer","___core_SchemaNormalizer","Logger","___utils_Logger","WizardLayout","render","schema","modelName","engine","onSubmit","wizard","Wizard","renderMode","showNextButton","complete","uiLayout","Array","isArray","warn","forEach","element","type","step","WizardStep","title","label","validated","form","SimpleForm","editable","layout","labelSpanXL","labelSpanL","labelSpanM","labelSpanS","adjustLabelSpan","emptySpanXL","emptySpanL","emptySpanM","emptySpanS","columnsXL","columnsL","columnsM","singleContainerFullSize","elements","childElement","this","_renderElementInForm","addContent","addStep","scope","startsWith","error","meta","bindingPath","propKey","resolveScope","labelText","ui","Label","text","required","effectiveMeta","widget","control","generateField","fullWidth","sap","require","GridData","setLayoutData","span","message","__exports","__esModule"],"sources":["WizardLayout.ts"],"sourcesContent":["/**\n * @file WizardLayout.ts\n * @description Generates a fully responsive SAP Fiori Wizard layout.\n */\n\nimport Wizard from \"sap/m/Wizard\";\nimport WizardStep from \"sap/m/WizardStep\";\nimport SimpleForm from \"sap/ui/layout/form/SimpleForm\";\nimport Label from \"sap/m/Label\";\nimport VBox from \"sap/m/VBox\";\nimport { IPropertyMetadata, ISchema, ILayoutElement } from \"../interfaces/ISchema\";\nimport { ILayoutManager } from \"../interfaces/ILayoutManager\";\nimport { Engine } from \"../core/Engine\";\nimport { SchemaNormalizer } from \"../core/SchemaNormalizer\";\nimport { Logger } from \"../utils/Logger\";\nimport Control from \"sap/ui/core/Control\";\n\n/**\n * Layout Manager responsible for generating a responsive SAP Fiori Wizard.\n * It segments the schema fields into discrete Wizard Steps based on `uiLayout` elements \n * of type `Group` or `WizardStep`.\n * \n * @namespace nz.co.siliconst.ui5.metaui.layouts\n * @public\n */\nexport class WizardLayout implements ILayoutManager {\n /**\n * Renders the JSON Schema properties into a paginated UI5 Wizard using uiLayout.\n * \n * @param schema The active JSON schema object.\n * @param modelName The bound UI5 model name.\n * @param engine The central orchestrator for delegating plugin generation.\n * @param onSubmit Hook executed when the Wizard's native 'complete' event is fired.\n * @returns {Control} The generated sap.m.Wizard control.\n */\n public render(schema: ISchema, modelName: string, engine: Engine, onSubmit?: () => void): Control {\n const wizard = new Wizard({\n renderMode: \"Page\",\n showNextButton: true,\n complete: function() {\n if (onSubmit) onSubmit();\n }\n });\n\n if (!schema.uiLayout || !Array.isArray(schema.uiLayout)) {\n Logger.warn(\"[MetaUI] Missing 'uiLayout' array in wizard schema. Wizard will not render any steps.\");\n return wizard;\n }\n\n schema.uiLayout.forEach((element: ILayoutElement) => {\n if (element.type === \"Group\" || element.type === \"WizardStep\") {\n const step = new WizardStep({\n title: element.label || \"Step\",\n validated: true // The PipelineManager handles global validation, wizard step validation can be local later\n });\n\n const form = new SimpleForm({\n editable: true,\n layout: \"ResponsiveGridLayout\",\n labelSpanXL: 4, labelSpanL: 4, labelSpanM: 4, labelSpanS: 12,\n adjustLabelSpan: false,\n emptySpanXL: 0, emptySpanL: 0, emptySpanM: 0, emptySpanS: 0,\n columnsXL: 1, columnsL: 1, columnsM: 1,\n singleContainerFullSize: false\n });\n \n if (element.elements && Array.isArray(element.elements)) {\n element.elements.forEach(childElement => {\n this._renderElementInForm(form, childElement, schema, modelName, engine);\n });\n }\n\n step.addContent(form);\n wizard.addStep(step);\n } else {\n Logger.warn(`[MetaUI] Top-level element '${element.type}' inside WizardLayout must be 'Group' or 'WizardStep'.`, \"\", \"WizardLayout\");\n }\n });\n\n return wizard;\n }\n\n /**\n * Synthesizes a field into the wizard step form.\n * @param form The SimpleForm belonging to the step.\n * @param element The layout element definition.\n * @param schema The schema reference.\n * @param modelName The UI5 data model name.\n * @param engine The core Engine instance.\n */\n private _renderElementInForm(form: SimpleForm, element: ILayoutElement, schema: ISchema, modelName: string, engine: Engine): void {\n if (element.type === \"Control\") {\n if (!element.scope || !element.scope.startsWith(\"#/properties/\")) {\n Logger.error(`[MetaUI] Invalid scope '${element.scope}' in uiLayout Control.`, \"\", \"WizardLayout\");\n return;\n }\n \n const { meta, bindingPath, propKey } = SchemaNormalizer.resolveScope(schema, element.scope);\n \n if (!meta) {\n Logger.error(`[MetaUI] Property '${propKey}' not found in schema definitions.`, \"\", \"WizardLayout\");\n return;\n }\n\n try {\n const labelText = element.label || meta.ui?.label || propKey;\n const label = new Label({\n text: labelText,\n required: meta.required\n });\n\n const effectiveMeta = { ...meta };\n if (element.widget) {\n effectiveMeta.ui = { ...meta.ui, widget: element.widget };\n }\n\n const control = engine.generateField(effectiveMeta, `/${bindingPath}`, modelName);\n\n if (effectiveMeta.ui?.fullWidth) {\n sap.ui.require([\"sap/ui/layout/GridData\"], (GridData: typeof import(\"sap/ui/layout/GridData\").default) => {\n control.setLayoutData(new GridData({ span: \"XL12 L12 M12 S12\" }));\n });\n }\n\n form.addContent(label);\n form.addContent(control);\n } catch (error) {\n Logger.error(`[MetaUI] Failed to render Wizard field ${propKey}`, (error as Error).message, \"WizardLayout\");\n form.addContent(new Label({ text: propKey }));\n }\n } else {\n Logger.warn(`[MetaUI] Nested groups within Wizard steps are not fully supported in SimpleForm yet.`, \"\", \"WizardLayout\");\n }\n }\n}\n"],"mappings":"sLAaSA,EAAgBC,EAAA,0BAChBC,EAAMC,EAAA,UAWR,MAAMC,EAUFC,OAAOC,EAAiBC,EAAmBC,EAAgBC,GAC9D,MAAMC,EAAS,IAAIC,EAAO,CACtBC,WAAY,OACZC,eAAgB,KAChBC,SAAU,WACN,GAAIL,EAAUA,GAClB,IAGJ,IAAKH,EAAOS,WAAaC,MAAMC,QAAQX,EAAOS,UAAW,CACrDb,EAAOgB,KAAK,yFACZ,OAAOR,CACX,CAEAJ,EAAOS,SAASI,QAASC,IACrB,GAAIA,EAAQC,OAAS,SAAWD,EAAQC,OAAS,aAAc,CAC3D,MAAMC,EAAO,IAAIC,EAAW,CACxBC,MAAOJ,EAAQK,OAAS,OACxBC,UAAW,OAGf,MAAMC,EAAO,IAAIC,EAAW,CACxBC,SAAU,KACVC,OAAQ,uBACRC,YAAa,EAAGC,WAAY,EAAGC,WAAY,EAAGC,WAAY,GAC1DC,gBAAiB,MACjBC,YAAa,EAAGC,WAAY,EAAGC,WAAY,EAAGC,WAAY,EAC1DC,UAAW,EAAGC,SAAU,EAAGC,SAAU,EACrCC,wBAAyB,QAG7B,GAAIvB,EAAQwB,UAAY5B,MAAMC,QAAQG,EAAQwB,UAAW,CACrDxB,EAAQwB,SAASzB,QAAQ0B,IACrBC,KAAKC,qBAAqBpB,EAAMkB,EAAcvC,EAAQC,EAAWC,IAEzE,CAEAc,EAAK0B,WAAWrB,GAChBjB,EAAOuC,QAAQ3B,EACnB,KAAO,CACHpB,EAAOgB,KAAK,+BAA+BE,EAAQC,6DAA8D,GAAI,eACzH,IAGJ,OAAOX,CACX,CAUQqC,qBAAqBpB,EAAkBP,EAAyBd,EAAiBC,EAAmBC,GACxG,GAAIY,EAAQC,OAAS,UAAW,CAC5B,IAAKD,EAAQ8B,QAAU9B,EAAQ8B,MAAMC,WAAW,iBAAkB,CAC9DjD,EAAOkD,MAAM,2BAA2BhC,EAAQ8B,8BAA+B,GAAI,gBACnF,MACJ,CAEA,MAAMG,KAAEA,EAAIC,YAAEA,EAAWC,QAAEA,GAAYvD,EAAiBwD,aAAalD,EAAQc,EAAQ8B,OAErF,IAAKG,EAAM,CACPnD,EAAOkD,MAAM,sBAAsBG,sCAA6C,GAAI,gBACpF,MACJ,CAEA,IACI,MAAME,EAAYrC,EAAQK,OAAS4B,EAAKK,IAAIjC,OAAS8B,EACrD,MAAM9B,EAAQ,IAAIkC,EAAM,CACpBC,KAAMH,EACNI,SAAUR,EAAKQ,WAGnB,MAAMC,EAAgB,IAAKT,GAC3B,GAAIjC,EAAQ2C,OAAQ,CAChBD,EAAcJ,GAAK,IAAKL,EAAKK,GAAIK,OAAQ3C,EAAQ2C,OACrD,CAEA,MAAMC,EAAUxD,EAAOyD,cAAcH,EAAe,IAAIR,IAAe/C,GAEvE,GAAIuD,EAAcJ,IAAIQ,UAAW,CAC7BC,IAAIT,GAAGU,QAAQ,CAAC,0BAA4BC,IACxCL,EAAQM,cAAc,IAAID,EAAS,CAAEE,KAAM,uBAEnD,CAEA5C,EAAKqB,WAAWvB,GAChBE,EAAKqB,WAAWgB,EACpB,CAAE,MAAOZ,GACLlD,EAAOkD,MAAM,0CAA0CG,IAAYH,EAAgBoB,QAAS,gBAC5F7C,EAAKqB,WAAW,IAAIW,EAAM,CAAEC,KAAML,IACtC,CACJ,KAAO,CACHrD,EAAOgB,KAAK,wFAAyF,GAAI,eAC7G,CACJ,EACH,IAAAuD,EAAA,CAAAC,WAAA,MAAAD,EAAArE,eAAA,OAAAqE,CAAA","ignoreList":[]}
1
+ {"version":3,"file":"WizardLayout.js","names":["SchemaNormalizer","___core_SchemaNormalizer","Logger","___utils_Logger","WizardLayout","render","schema","modelName","engine","onSubmit","uiLayout","Array","isArray","warn","VBox","stepElements","filter","e","type","length","totalSteps","stepForms","stepFieldPaths","forEach","element","fieldPaths","form","this","_buildStepForm","push","currentStepIndex","stepTitleControl","MTitle","level","stepCounterLabel","Text","progressBar","ProgressIndicator","showValue","state","height","addStyleClass","contentArea","width","prevButton","Button","text","icon","enabled","press","navigateTo","nextButton","iconFirst","handleNextPress","index","error","isLastStep","setText","label","setPercentValue","removeAllItems","addItem","setEnabled","setIcon","_validateStep","debug","host","sm","getStateManager","payload","extractPayload","isPrevented","isNavigated","advance","fireEvent","stepIndex","preventDefault","addError","fieldPath","errorMessage","plugin","getPluginByPath","setVisualValidationState","resumeNavigation","navBar","HBox","justifyContent","alignItems","items","header","allValid","path","result","validate","isValid","reportSchemaError","stepElement","SimpleForm","editable","layout","labelSpanXL","labelSpanL","labelSpanM","labelSpanS","adjustLabelSpan","emptySpanXL","emptySpanL","emptySpanM","emptySpanS","columnsXL","columnsL","columnsM","singleContainerFullSize","elements","childElement","_renderElementInForm","addContent","CoreTitle","scope","startsWith","meta","bindingPath","propKey","resolveScope","labelText","ui","Label","required","effectiveMeta","widget","absolutePath","control","generateField","fullWidth","sap","require","GridData","setLayoutData","span","message","__exports","__esModule"],"sources":["WizardLayout.ts"],"sourcesContent":["/**\n * @file WizardLayout.ts\n * @description MetaUI custom step-by-step wizard navigator.\n *\n * Architecture Decision:\n * SAP's sap.m.Wizard in renderMode \"Page\" requires a NavContainer ancestor in the DOM,\n * which MetaUI's GeneratorHost VBox does not provide. Using sap.m.Wizard in the default\n * \"Scroll\" mode renders ALL steps simultaneously, which is not desired behavior.\n *\n * Solution: Implement a fully custom step navigator using plain VBox/HBox/Button controls.\n * This gives MetaUI complete control over step visibility, per-step field validation,\n * and the beforeLayoutSectionChange async event API — with no dependency on the broken\n * Wizard container API.\n */\n\nimport SimpleForm from \"sap/ui/layout/form/SimpleForm\";\nimport Label from \"sap/m/Label\";\nimport VBox from \"sap/m/VBox\";\nimport HBox from \"sap/m/HBox\";\nimport Button from \"sap/m/Button\";\nimport ProgressIndicator from \"sap/m/ProgressIndicator\";\nimport MTitle from \"sap/m/Title\"; // sap.m.Title IS a Control → safe inside HBox.items\nimport CoreTitle from \"sap/ui/core/Title\"; // sap.ui.core.Title is an Element → SimpleForm section headers ONLY\nimport Text from \"sap/m/Text\";\nimport { IPropertyMetadata, ISchema, ILayoutElement } from \"../interfaces/ISchema\";\nimport { IPlugin } from \"../interfaces/IPlugin\";\nimport { ILayoutManager } from \"../interfaces/ILayoutManager\";\nimport { Engine } from \"../core/Engine\";\nimport { SchemaNormalizer } from \"../core/SchemaNormalizer\";\nimport { Logger } from \"../utils/Logger\";\nimport Control from \"sap/ui/core/Control\";\n\n/**\n * Minimal structural contract for accessing the hosting GeneratorHost without importing\n * it directly (which would create a circular dependency between WizardLayout ↔ GeneratorHost).\n */\ninterface IWizardCapableHost {\n /** Returns the active StateManager. Used to extract a payload snapshot at step-change time. */\n getStateManager(): { extractPayload(): Record<string, unknown> } | null;\n /** Fires a UI5 event upward on the host control. */\n fireEvent(eventName: string, params: Record<string, unknown>): void;\n}\n\n/**\n * Layout Manager that generates a custom paginated step navigator.\n * Renders exactly one step at a time, validates current-step fields before advancing,\n * and fires `beforeLayoutSectionChange` with a full async API before each step transition.\n *\n * @namespace nz.co.siliconst.ui5.metaui.layouts\n * @public\n */\nexport class WizardLayout implements ILayoutManager {\n /**\n * Renders the wizard as a custom step-by-step navigator.\n *\n * @param schema The active JSON schema object containing `uiLayout` step groups.\n * @param modelName The bound UI5 model name for data bindings.\n * @param engine The central Engine orchestrator for field generation and validation.\n * @param onSubmit Hook executed when the user completes the final step successfully.\n * @returns {Control} A VBox root container comprising the step header, content, and navigation.\n */\n public render(schema: ISchema, modelName: string, engine: Engine, onSubmit?: () => void): Control {\n if (!schema.uiLayout || !Array.isArray(schema.uiLayout)) {\n Logger.warn(\"[MetaUI WizardLayout] Missing 'uiLayout' array in schema. Cannot build step navigator.\", \"\", \"WizardLayout\");\n return new VBox();\n }\n\n // Filter valid step-level elements. Both \"Group\" and \"WizardStep\" act as step containers.\n const stepElements = schema.uiLayout.filter(\n (e: ILayoutElement) => e.type === \"Group\" || e.type === \"WizardStep\"\n );\n\n if (stepElements.length === 0) {\n Logger.warn(\"[MetaUI WizardLayout] No Group or WizardStep elements found in uiLayout.\", \"\", \"WizardLayout\");\n return new VBox();\n }\n\n const totalSteps = stepElements.length;\n\n // --- Phase 1: Build all step forms and track field binding paths per step ---\n // Each step form is built eagerly so that plugins are registered in the Engine\n // and are available for validation via engine.getPluginByPath() on any step.\n const stepForms: SimpleForm[] = [];\n // stepFieldPaths[i] = all binding paths registered when building step i's fields.\n // Used by _validateStep to run targeted per-step validation.\n const stepFieldPaths: string[][] = [];\n\n stepElements.forEach((element: ILayoutElement) => {\n const fieldPaths: string[] = [];\n const form = this._buildStepForm(element, schema, modelName, engine, fieldPaths);\n stepForms.push(form);\n stepFieldPaths.push(fieldPaths);\n });\n\n // --- Phase 2: Build the navigator UI ---\n // Navigation state. Lives in closure; mutated by navigateTo() on each step transition.\n let currentStepIndex = 0;\n\n // Header: step title (sap.m.Title — a proper Control) + step counter label + progress bar\n const stepTitleControl = new MTitle({ level: \"H3\" });\n const stepCounterLabel = new Text();\n const progressBar = new ProgressIndicator({\n showValue: false,\n state: \"None\",\n height: \"0.5rem\"\n }).addStyleClass(\"metaUIWizardProgress\");\n\n // Content: single-child VBox that swaps its contents to the current step form\n const contentArea = new VBox({ width: \"100%\" }).addStyleClass(\"metaUIWizardContent\");\n\n // Navigation: Previous (left) / Next|Complete (right)\n const prevButton = new Button({\n text: \"Previous\",\n icon: \"sap-icon://navigation-left-arrow\",\n enabled: false,\n press: () => navigateTo(currentStepIndex - 1)\n });\n\n const nextButton = new Button({\n type: \"Emphasized\",\n text: totalSteps === 1 ? \"Complete\" : \"Next Step\",\n icon: \"sap-icon://navigation-right-arrow\",\n iconFirst: false,\n press: () => handleNextPress()\n });\n\n // --- Phase 3: Navigation logic ---\n\n /**\n * Physically transitions the navigator to the given step index.\n * Updates the header, content, and navigation button states.\n *\n * @param index The target step index (0-based).\n */\n const navigateTo = (index: number): void => {\n if (index < 0 || index >= totalSteps) {\n Logger.error(\"[MetaUI WizardLayout]\", `Invalid navigation target: step ${index}`, \"WizardLayout\");\n return;\n }\n\n currentStepIndex = index;\n const element = stepElements[currentStepIndex];\n const isLastStep = currentStepIndex === totalSteps - 1;\n\n // Update step header\n stepTitleControl.setText(element.label || `Step ${currentStepIndex + 1}`);\n stepCounterLabel.setText(`Step ${currentStepIndex + 1} of ${totalSteps}`);\n progressBar.setPercentValue(((currentStepIndex + 1) / totalSteps) * 100);\n\n // Swap the content area to show only the current step's form\n contentArea.removeAllItems();\n contentArea.addItem(stepForms[currentStepIndex]);\n\n // Update navigation controls\n prevButton.setEnabled(currentStepIndex > 0);\n nextButton.setText(isLastStep ? \"Complete\" : \"Next Step\");\n nextButton.setIcon(isLastStep ? \"sap-icon://accept\" : \"sap-icon://navigation-right-arrow\");\n };\n\n /**\n * Called when the user presses the Next/Complete button.\n * Executes the following pipeline in sequence:\n * 1. Per-step field validation (synchronous, local).\n * 2. If last step → fires onSubmit.\n * 3. Otherwise → fires `beforeLayoutSectionChange` with full async API.\n * 4. If not prevented → calls navigateTo(next).\n */\n const handleNextPress = (): void => {\n // Step 1: Validate only the current step's fields.\n // This gives immediate visual feedback (red borders) on errors before any event fires.\n if (!this._validateStep(stepFieldPaths[currentStepIndex], engine)) {\n Logger.debug(\"[MetaUI WizardLayout]\", `Step ${currentStepIndex} failed local validation. Blocking navigation.`, \"WizardLayout\");\n return;\n }\n\n // Step 2: If this is the final step, treat Next as Complete.\n if (currentStepIndex === totalSteps - 1) {\n if (onSubmit) onSubmit();\n return;\n }\n\n // Step 3: Fire beforeLayoutSectionChange to give the consumer a pre-navigation hook.\n const host = engine.host as IWizardCapableHost | null;\n\n if (!host) {\n // No upstream host to notify — advance directly.\n navigateTo(currentStepIndex + 1);\n return;\n }\n\n const sm = host.getStateManager();\n const payload: Record<string, unknown> = sm ? sm.extractPayload() : {};\n\n // Guard: prevents navigateTo() from being called more than once\n // if both preventDefault + resumeNavigation are called by a consumer.\n let isPrevented = false;\n let isNavigated = false;\n\n const advance = (): void => {\n if (!isNavigated) {\n isNavigated = true;\n navigateTo(currentStepIndex + 1);\n }\n };\n\n host.fireEvent(\"beforeLayoutSectionChange\", {\n /**\n * The 0-based index of the step the user is navigating AWAY FROM.\n */\n stepIndex: currentStepIndex,\n\n /**\n * A live snapshot of the full form payload at the moment of the transition.\n */\n payload,\n\n /**\n * Blocks navigation synchronously. Call this at the start of an async check to\n * prevent the wizard from advancing while waiting for a backend response.\n * Call resumeNavigation() after the check passes to allow the advance.\n */\n preventDefault: () => {\n isPrevented = true;\n },\n\n /**\n * Blocks navigation AND paints a specific field with an error state.\n * @param fieldPath The full binding path of the field to mark invalid.\n * @param errorMessage The error message to display on the field.\n */\n addError: (fieldPath: string, errorMessage: string) => {\n isPrevented = true;\n const plugin: IPlugin | undefined = engine.getPluginByPath(fieldPath);\n if (plugin && typeof plugin.setVisualValidationState === \"function\") {\n plugin.setVisualValidationState(false, errorMessage);\n }\n },\n\n /**\n * Explicitly allows navigation after a prior `preventDefault()` call.\n * Intended for async consumer patterns (e.g., backend validation Promises).\n * Calling this causes the wizard to advance to the next step immediately.\n */\n resumeNavigation: () => {\n advance();\n }\n });\n\n // Step 4: If the consumer did not call preventDefault(), advance immediately.\n if (!isPrevented) {\n advance();\n }\n };\n\n // Initialize: show Step 0 with all state set correctly.\n navigateTo(0);\n\n // --- Phase 4: Assemble the root container ---\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const navBar = new HBox({\n width: \"100%\",\n justifyContent: \"SpaceBetween\",\n alignItems: \"Center\",\n items: [prevButton, nextButton]\n } as any).addStyleClass(\"sapUiSmallMarginTop\");\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const header = new VBox({\n width: \"100%\",\n items: [\n new HBox({\n justifyContent: \"SpaceBetween\",\n alignItems: \"Center\",\n width: \"100%\",\n items: [stepTitleControl, stepCounterLabel]\n } as any),\n progressBar\n ]\n }).addStyleClass(\"sapUiSmallMarginBottom\");\n\n return new VBox({\n width: \"100%\",\n items: [header, contentArea, navBar]\n });\n }\n\n /**\n * Validates all fields registered during a specific step's form build.\n *\n * Routes error painting through `engine.reportSchemaError()` → `resolveVisualState()`\n * → `plugin.setVisualValidationState()`. This is the single authoritative path for\n * painting red borders in MetaUI, and correctly handles both default and\n * `useMessageManager` modes.\n *\n * @param fieldPaths The list of binding paths collected during the step's form build.\n * @param engine The Engine instance that holds the plugin registry and validation ledger.\n * @returns {boolean} True if all fields are valid, false if any failed.\n */\n private _validateStep(fieldPaths: string[], engine: Engine): boolean {\n let allValid = true;\n\n for (const path of fieldPaths) {\n const plugin = engine.getPluginByPath(path);\n if (!plugin) continue;\n\n const result = plugin.validate();\n\n if (!result.isValid) {\n // Route through the Engine's validation ledger.\n // reportSchemaError → resolveVisualState → plugin.setVisualValidationState\n // This is the same path used by triggerSubmit and the PBRE.\n engine.reportSchemaError(path, result.errorMessage || \"This field is required.\");\n allValid = false;\n } else {\n // Clearing null removes the error from the ledger and resets the visual state.\n engine.reportSchemaError(path, null);\n }\n }\n\n return allValid;\n }\n\n /**\n * Constructs a SimpleForm for a single wizard step, recursively rendering all\n * child layout elements and collecting their binding paths into `fieldPaths`.\n *\n * @param stepElement The top-level Group/WizardStep layout element for this step.\n * @param schema The active JSON schema.\n * @param modelName The UI5 JSONModel alias for data binding.\n * @param engine The Engine instance for field generation.\n * @param fieldPaths Collector array — all binding paths generated for this step are pushed here.\n * @returns {SimpleForm} The assembled SimpleForm for this wizard step.\n */\n private _buildStepForm(\n stepElement: ILayoutElement,\n schema: ISchema,\n modelName: string,\n engine: Engine,\n fieldPaths: string[]\n ): SimpleForm {\n const form = new SimpleForm({\n editable: true,\n layout: \"ResponsiveGridLayout\",\n labelSpanXL: 4, labelSpanL: 4, labelSpanM: 4, labelSpanS: 12,\n adjustLabelSpan: false,\n emptySpanXL: 0, emptySpanL: 0, emptySpanM: 0, emptySpanS: 0,\n columnsXL: 1, columnsL: 1, columnsM: 1,\n singleContainerFullSize: false\n });\n\n if (stepElement.elements && Array.isArray(stepElement.elements)) {\n stepElement.elements.forEach((childElement: ILayoutElement) => {\n this._renderElementInForm(form, childElement, schema, modelName, engine, fieldPaths);\n });\n }\n\n return form;\n }\n\n /**\n * Recursively renders a single layout element into a SimpleForm.\n * For `Group` elements, adds a Title and recurses into children.\n * For `Control` elements, resolves the schema scope, generates the plugin control,\n * and pushes the binding path to `fieldPaths` for per-step validation tracking.\n *\n * @param form The target SimpleForm to append content to.\n * @param element The layout element to render.\n * @param schema The active JSON schema.\n * @param modelName The UI5 JSONModel alias for data binding.\n * @param engine The Engine instance for field generation.\n * @param fieldPaths Collector array for binding path tracking.\n */\n private _renderElementInForm(\n form: SimpleForm,\n element: ILayoutElement,\n schema: ISchema,\n modelName: string,\n engine: Engine,\n fieldPaths: string[]\n ): void {\n if (element.type === \"Group\") {\n if (element.label) {\n // sap.ui.core.Title (CoreTitle) is an Element, not a Control.\n // It is ONLY valid inside a SimpleForm's content aggregation as a section header.\n form.addContent(new CoreTitle({ text: element.label }));\n }\n if (element.elements && Array.isArray(element.elements)) {\n element.elements.forEach((childElement: ILayoutElement) => {\n this._renderElementInForm(form, childElement, schema, modelName, engine, fieldPaths);\n });\n }\n return;\n }\n\n if (element.type === \"Control\") {\n if (!element.scope || !element.scope.startsWith(\"#/properties/\")) {\n Logger.error(`[MetaUI WizardLayout] Invalid scope '${element.scope}' — must start with '#/properties/'.`, \"\", \"WizardLayout\");\n return;\n }\n\n const { meta, bindingPath, propKey } = SchemaNormalizer.resolveScope(schema, element.scope);\n\n if (!meta) {\n Logger.error(`[MetaUI WizardLayout] Property '${propKey}' not found in schema.`, \"\", \"WizardLayout\");\n return;\n }\n\n try {\n const labelText = element.label || meta.ui?.label || propKey;\n const label = new Label({\n text: labelText,\n // meta.required may be boolean or string[] at schema object level;\n // Label.required only accepts boolean — normalize it.\n required: meta.required === true\n });\n\n const effectiveMeta: IPropertyMetadata = { ...meta };\n if (element.widget) {\n effectiveMeta.ui = { ...(meta.ui || {}), widget: element.widget };\n }\n\n const absolutePath = `/${bindingPath}`;\n const control = engine.generateField(effectiveMeta, absolutePath, modelName);\n\n // Track this path so _validateStep can target exactly the fields built for this step.\n fieldPaths.push(absolutePath);\n\n if (effectiveMeta.ui?.fullWidth) {\n sap.ui.require([\"sap/ui/layout/GridData\"], (GridData: typeof import(\"sap/ui/layout/GridData\").default) => {\n control.setLayoutData(new GridData({ span: \"XL12 L12 M12 S12\" }));\n });\n }\n\n form.addContent(label);\n form.addContent(control);\n } catch (error) {\n Logger.error(`[MetaUI WizardLayout] Failed to render field '${propKey}'`, (error as Error).message, \"WizardLayout\");\n form.addContent(new Label({ text: propKey }));\n }\n return;\n }\n\n Logger.warn(`[MetaUI WizardLayout] Unsupported element type '${element.type}' inside a wizard step.`, \"\", \"WizardLayout\");\n }\n}\n"],"mappings":"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","ignoreList":[]}