@praxisui/crud 9.0.0-beta.4 → 9.0.0-beta.40

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.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Injectable, InjectionToken, inject, input, signal, computed, effect, ChangeDetectionStrategy, Component, EventEmitter, DestroyRef, ChangeDetectorRef, Injector, ViewChild, Output, Input, Inject, ENVIRONMENT_INITIALIZER } from '@angular/core';
2
+ import { Injectable, InjectionToken, inject, input, signal, computed, effect, ChangeDetectionStrategy, Component, EventEmitter, DestroyRef, ChangeDetectorRef, Injector, ViewChild, Output, Input, Inject, ViewEncapsulation, ENVIRONMENT_INITIALIZER } from '@angular/core';
3
3
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
4
4
  import { HttpClient } from '@angular/common/http';
5
5
  import { Router, ActivatedRoute, RouterLink } from '@angular/router';
@@ -10,6 +10,7 @@ import { ASYNC_CONFIG_STORAGE, GlobalConfigService, CrudOperationResolutionServi
10
10
  import { SettingsPanelService } from '@praxisui/settings-panel';
11
11
  import { PraxisTableInlineAuthoringEditorComponent, PraxisTable } from '@praxisui/table';
12
12
  import { ConfirmDialogComponent } from '@praxisui/dynamic-fields';
13
+ import { take, filter } from 'rxjs/operators';
13
14
  import * as i1 from '@angular/material/dialog';
14
15
  import { MatDialogRef, MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
15
16
  export { MAT_DIALOG_DATA as DIALOG_DATA } from '@angular/material/dialog';
@@ -34,7 +35,6 @@ import { MatSlideToggleModule } from '@angular/material/slide-toggle';
34
35
  import * as i10 from '@angular/material/tabs';
35
36
  import { MatTabsModule } from '@angular/material/tabs';
36
37
  import { PraxisDynamicForm } from '@praxisui/dynamic-form';
37
- import { filter, take } from 'rxjs/operators';
38
38
 
39
39
  class DialogService {
40
40
  matDialog;
@@ -95,22 +95,6 @@ class CrudLauncherService {
95
95
  await this.router.navigateByUrl(url);
96
96
  return { mode };
97
97
  }
98
- if (mode === 'drawer' && this.drawerAdapter) {
99
- const actionForLaunch = this.resolveActionForLaunch(merged.action, merged.metadata);
100
- const inputs = this.mapInputs(actionForLaunch, row, merged.metadata, runtime);
101
- const idField = merged.metadata.resource?.idField ?? 'id';
102
- if (row && inputs[idField] === undefined && row[idField] !== undefined) {
103
- inputs[idField] = row[idField];
104
- }
105
- await Promise.resolve(this.drawerAdapter.open({
106
- action: actionForLaunch,
107
- metadata: merged.metadata,
108
- inputs,
109
- onClose: drawerCallbacks?.onClose,
110
- onResult: drawerCallbacks?.onResult,
111
- }));
112
- return { mode };
113
- }
114
98
  const actionForLaunch = this.resolveActionForLaunch(merged.action, merged.metadata);
115
99
  if (!actionForLaunch.formId) {
116
100
  throw new Error(`formId not provided for action ${actionForLaunch.action}`);
@@ -123,6 +107,16 @@ class CrudLauncherService {
123
107
  row[idField] !== undefined) {
124
108
  inputs[idField] = row[idField];
125
109
  }
110
+ if (mode === 'drawer' && this.drawerAdapter) {
111
+ await Promise.resolve(this.drawerAdapter.open({
112
+ action: actionForLaunch,
113
+ metadata: merged.metadata,
114
+ inputs,
115
+ onClose: drawerCallbacks?.onClose,
116
+ onResult: drawerCallbacks?.onResult,
117
+ }));
118
+ return { mode };
119
+ }
126
120
  const modalCfg = { ...(merged.metadata.defaults?.modal || {}) };
127
121
  console.debug('[CRUD:Launcher] opening dialog with:', {
128
122
  action: merged.action.action,
@@ -131,10 +125,8 @@ class CrudLauncherService {
131
125
  modalCfg,
132
126
  resourcePath: merged.metadata.resource?.path ?? merged.metadata.table?.resourcePath,
133
127
  });
134
- const panelClasses = ['pfx-dialog-pane', 'pfx-dialog-frosted'];
135
- if (modalCfg.panelClass) {
136
- panelClasses.push(modalCfg.panelClass);
137
- }
128
+ const drawerMode = mode === 'drawer';
129
+ const panelClasses = mergeClassList(['pfx-dialog-pane', drawerMode ? 'pfx-drawer-pane' : 'pfx-dialog-frosted'], modalCfg.panelClass);
138
130
  // Backdrop style presets
139
131
  const backdropClasses = [];
140
132
  const style = modalCfg.backdropStyle;
@@ -147,20 +139,44 @@ class CrudLauncherService {
147
139
  else if (style === 'transparent') {
148
140
  backdropClasses.push('pfx-transparent-backdrop');
149
141
  }
150
- if (modalCfg.backdropClass) {
151
- backdropClasses.push(modalCfg.backdropClass);
152
- }
142
+ const mergedBackdropClasses = mergeClassList(backdropClasses, modalCfg.backdropClass);
153
143
  const ref = await this.dialog.openAsync(() => Promise.resolve().then(function () { return dynamicFormDialogHost_component; }).then((m) => m.DynamicFormDialogHostComponent), {
154
144
  ...modalCfg,
155
145
  panelClass: panelClasses,
156
- backdropClass: backdropClasses,
146
+ backdropClass: mergedBackdropClasses,
157
147
  autoFocus: modalCfg.autoFocus ?? true,
158
148
  restoreFocus: modalCfg.restoreFocus ?? true,
159
- minWidth: '360px',
160
- maxWidth: '95vw',
149
+ minWidth: drawerMode ? (modalCfg.minWidth ?? '0') : '360px',
150
+ width: drawerMode ? (modalCfg.width ?? 'min(560px, 100vw)') : modalCfg.width,
151
+ height: drawerMode ? (modalCfg.height ?? '100dvh') : modalCfg.height,
152
+ maxWidth: drawerMode ? (modalCfg.maxWidth ?? '100vw') : '95vw',
153
+ maxHeight: drawerMode ? (modalCfg.maxHeight ?? '100dvh') : modalCfg.maxHeight,
154
+ position: drawerMode ? (modalCfg.position ?? { right: '0', top: '0' }) : modalCfg.position,
161
155
  ariaLabelledBy: 'crudDialogTitle',
162
- data: { action: actionForLaunch, row, metadata: merged.metadata, inputs },
156
+ data: {
157
+ action: actionForLaunch,
158
+ row,
159
+ metadata: merged.metadata,
160
+ inputs,
161
+ presentation: drawerMode ? 'drawer' : 'modal',
162
+ },
163
163
  });
164
+ if (drawerMode) {
165
+ ref
166
+ .afterClosed()
167
+ .pipe(take(1))
168
+ .subscribe((closedValue) => {
169
+ const result = toCrudDrawerResult(closedValue);
170
+ drawerCallbacks?.onClose?.();
171
+ if (result?.type) {
172
+ drawerCallbacks?.onResult?.(result);
173
+ }
174
+ else {
175
+ drawerCallbacks?.onResult?.({ type: 'close' });
176
+ }
177
+ });
178
+ return { mode, ref };
179
+ }
164
180
  return { mode, ref };
165
181
  }
166
182
  resolveOpenMode(action, metadata) {
@@ -248,6 +264,9 @@ class CrudLauncherService {
248
264
  if (resolved.apiUrlEntry != null) {
249
265
  inputs['apiUrlEntry'] = resolved.apiUrlEntry;
250
266
  }
267
+ if (resolved.layoutPolicy != null) {
268
+ inputs['layoutPolicy'] = resolved.layoutPolicy;
269
+ }
251
270
  if (action.form?.initialValue != null) {
252
271
  inputs['initialValue'] = action.form.initialValue;
253
272
  }
@@ -274,12 +293,14 @@ class CrudLauncherService {
274
293
  submitMethod: action.form?.submitMethod ?? null,
275
294
  apiEndpointKey: action.form?.apiEndpointKey ?? null,
276
295
  apiUrlEntry: action.form?.apiUrlEntry ?? null,
296
+ layoutPolicy: action.form?.layoutPolicy ?? null,
277
297
  };
278
298
  }
279
299
  if (!this.isCanonicalCrudAction(action.action)) {
280
300
  return {
281
301
  apiEndpointKey: action.form?.apiEndpointKey ?? null,
282
302
  apiUrlEntry: action.form?.apiUrlEntry ?? null,
303
+ layoutPolicy: action.form?.layoutPolicy ?? null,
283
304
  };
284
305
  }
285
306
  const resourcePath = String(metadata.resource?.path ?? metadata.table?.resourcePath ?? '').trim();
@@ -309,6 +330,7 @@ class CrudLauncherService {
309
330
  submitMethod: resolved?.submitMethod ?? null,
310
331
  apiEndpointKey: action.form?.apiEndpointKey ?? metadata.resource?.endpointKey ?? null,
311
332
  apiUrlEntry: action.form?.apiUrlEntry ?? null,
333
+ layoutPolicy: action.form?.layoutPolicy ?? null,
312
334
  };
313
335
  }
314
336
  resolveRuntimeContract(action, row, metadata, runtime) {
@@ -392,6 +414,30 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
392
414
  type: Injectable,
393
415
  args: [{ providedIn: 'root' }]
394
416
  }] });
417
+ function mergeClassList(base, extra) {
418
+ if (!extra) {
419
+ return base;
420
+ }
421
+ if (typeof extra === 'string') {
422
+ return [...base, extra];
423
+ }
424
+ if (Array.isArray(extra)) {
425
+ return [...base, ...extra];
426
+ }
427
+ return [
428
+ ...base,
429
+ ...Object.keys(extra).filter((className) => !!extra[className]),
430
+ ];
431
+ }
432
+ function toCrudDrawerResult(value) {
433
+ if (!value || typeof value !== 'object') {
434
+ return undefined;
435
+ }
436
+ const result = value;
437
+ return result.type === 'save' || result.type === 'delete' || result.type === 'close'
438
+ ? result
439
+ : undefined;
440
+ }
395
441
 
396
442
  const DOCUMENT_KIND = 'praxis.crud.editor';
397
443
  const DOCUMENT_VERSION = 1;
@@ -3656,6 +3702,9 @@ class PraxisCrudComponent {
3656
3702
  links: this.resolveCrudRuntimeLinks(effectiveAction.action, row),
3657
3703
  });
3658
3704
  this.afterOpen.emit({ mode, action: effectiveAction.action });
3705
+ if (mode === 'drawer') {
3706
+ return;
3707
+ }
3659
3708
  if (!ref) {
3660
3709
  return;
3661
3710
  }
@@ -3999,7 +4048,7 @@ class PraxisCrudComponent {
3999
4048
  const providedAction = this.resolveProvidedWorkflowAction(normalizedAction, runtimeEvent?.actionConfig);
4000
4049
  const catalog = providedAction ? null : await this.resolveDiscoveredActionCatalog(row);
4001
4050
  const discoveredAction = providedAction || this.selectDiscoveredWorkflowAction(normalizedAction, catalog?.actions || []);
4002
- const resourcePath = String(this.resolveResourcePath(this.resolvedMetadata) || catalog?.resourcePath || '').trim();
4051
+ const resourcePath = String(catalog?.resourcePath || this.resolveResourcePath(this.resolvedMetadata) || '').trim();
4003
4052
  if (!discoveredAction || !resourcePath) {
4004
4053
  return false;
4005
4054
  }
@@ -4657,7 +4706,7 @@ class PraxisCrudComponent {
4657
4706
  />
4658
4707
  }
4659
4708
  }
4660
- `, isInline: true, styles: [":host{display:block;width:100%;min-width:0;max-width:100%}\n"], dependencies: [{ kind: "component", type: PraxisTable, selector: "praxis-table", inputs: ["config", "resourcePath", "data", "tableId", "componentInstanceId", "configPersistenceStrategy", "title", "subtitle", "icon", "autoDelete", "notifyIfOutdated", "snoozeMs", "autoOpenSettingsOnOutdated", "crudContext", "filterCriteria", "queryContext", "aiContext", "aiAssistantVoiceInputMode", "aiAssistantVoiceLanguage", "horizontalScroll", "enableCustomization", "dense"], outputs: ["rowClick", "widgetEvent", "rowDoubleClick", "rowExpansionChange", "rowAction", "toolbarAction", "bulkAction", "exportAction", "columnReorder", "columnReorderAttempt", "beforeDelete", "afterDelete", "deleteError", "beforeBulkDelete", "afterBulkDelete", "bulkDeleteError", "schemaStatusChange", "configChange", "metadataChange", "loadingStateChange", "collectionLinksChange", "selectionChange"] }, { kind: "component", type: EmptyStateCardComponent, selector: "praxis-empty-state-card", inputs: ["icon", "title", "description", "primaryAction", "secondaryActions", "inline", "tone"] }] });
4709
+ `, isInline: true, styles: [":host{display:block;width:100%;min-width:0;max-width:100%}\n"], dependencies: [{ kind: "component", type: PraxisTable, selector: "praxis-table", inputs: ["config", "resourcePath", "data", "tableId", "componentInstanceId", "configPersistenceStrategy", "title", "subtitle", "icon", "autoDelete", "notifyIfOutdated", "snoozeMs", "autoOpenSettingsOnOutdated", "crudContext", "filterCriteria", "queryContext", "aiContext", "aiAssistantVoiceInputMode", "aiAssistantVoiceLanguage", "horizontalScroll", "enableCustomization", "dense"], outputs: ["rowClick", "widgetEvent", "resourceEvent", "rowDoubleClick", "rowExpansionChange", "rowAction", "toolbarAction", "bulkAction", "exportAction", "columnReorder", "columnReorderAttempt", "columnResize", "beforeDelete", "afterDelete", "deleteError", "beforeBulkDelete", "afterBulkDelete", "bulkDeleteError", "schemaStatusChange", "configChange", "metadataChange", "loadingStateChange", "collectionLinksChange", "selectionChange"] }, { kind: "component", type: EmptyStateCardComponent, selector: "praxis-empty-state-card", inputs: ["icon", "title", "description", "primaryAction", "secondaryActions", "inline", "tone"] }] });
4661
4710
  }
4662
4711
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisCrudComponent, decorators: [{
4663
4712
  type: Component,
@@ -4742,6 +4791,7 @@ class DynamicFormDialogHostComponent {
4742
4791
  configStorage;
4743
4792
  formComp;
4744
4793
  modal = {};
4794
+ presentation = 'modal';
4745
4795
  maximized = false;
4746
4796
  initialSize = {};
4747
4797
  rememberState = false;
@@ -4756,6 +4806,7 @@ class DynamicFormDialogHostComponent {
4756
4806
  submitMethod;
4757
4807
  apiEndpointKey;
4758
4808
  apiUrlEntry;
4809
+ layoutPolicy;
4759
4810
  formActions;
4760
4811
  mode = 'create';
4761
4812
  backConfig;
@@ -4778,6 +4829,7 @@ class DynamicFormDialogHostComponent {
4778
4829
  this.crud = crud;
4779
4830
  this.configStorage = configStorage;
4780
4831
  this.dialogRef.disableClose = true;
4832
+ this.presentation = this.data.presentation === 'drawer' ? 'drawer' : 'modal';
4781
4833
  // i18n
4782
4834
  this.texts = {
4783
4835
  ...this.texts,
@@ -4812,6 +4864,7 @@ class DynamicFormDialogHostComponent {
4812
4864
  this.apiUrlEntry = this.data.inputs?.['apiUrlEntry'] ?? null;
4813
4865
  const act = this.data.action?.action;
4814
4866
  this.mode = act === 'edit' ? 'edit' : act === 'view' ? 'view' : 'create';
4867
+ this.layoutPolicy = this.resolveLayoutPolicy();
4815
4868
  this.formActions = this.resolveFormActions();
4816
4869
  // Back config: defaults from metadata/action, overridden by saved per-form config
4817
4870
  const defaults = (this.data.action?.back || this.data.metadata?.defaults?.back) || {};
@@ -4857,6 +4910,7 @@ class DynamicFormDialogHostComponent {
4857
4910
  'apiEndpointKey',
4858
4911
  'apiUrlEntry',
4859
4912
  'initialValue',
4913
+ 'layoutPolicy',
4860
4914
  ]);
4861
4915
  const explicit = inputs['initialValue'] && typeof inputs['initialValue'] === 'object'
4862
4916
  ? { ...inputs['initialValue'] }
@@ -4890,6 +4944,15 @@ class DynamicFormDialogHostComponent {
4890
4944
  },
4891
4945
  };
4892
4946
  }
4947
+ resolveLayoutPolicy() {
4948
+ const explicit = this.data.inputs?.['layoutPolicy'] ??
4949
+ this.data.action?.form?.layoutPolicy ??
4950
+ this.data.action?.layoutPolicy;
4951
+ if (explicit && typeof explicit === 'object') {
4952
+ return explicit;
4953
+ }
4954
+ return null;
4955
+ }
4893
4956
  resolveSubmitLabel() {
4894
4957
  const action = this.data.action ?? {};
4895
4958
  const explicit = stringOrUndefined(action.form?.submitLabel ??
@@ -4962,10 +5025,10 @@ class DynamicFormDialogHostComponent {
4962
5025
  ref
4963
5026
  .afterClosed()
4964
5027
  .pipe(filter((confirmed) => !!confirmed), takeUntilDestroyed(this.destroyRef))
4965
- .subscribe(() => this.dialogRef.close());
5028
+ .subscribe(() => this.dialogRef.close({ type: 'close' }));
4966
5029
  }
4967
5030
  else {
4968
- this.dialogRef.close();
5031
+ this.dialogRef.close({ type: 'close' });
4969
5032
  }
4970
5033
  }
4971
5034
  toggleMaximize(initial = false) {
@@ -5032,7 +5095,7 @@ class DynamicFormDialogHostComponent {
5032
5095
  }
5033
5096
  }
5034
5097
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DynamicFormDialogHostComponent, deps: [{ token: MatDialogRef }, { token: MAT_DIALOG_DATA }, { token: DialogService }, { token: i2$1.GenericCrudService }, { token: ASYNC_CONFIG_STORAGE }], target: i0.ɵɵFactoryTarget.Component });
5035
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: DynamicFormDialogHostComponent, isStandalone: true, selector: "praxis-dynamic-form-dialog-host", host: { properties: { "attr.data-density": "modal.density || \"default\"" }, classAttribute: "praxis-dialog" }, providers: [GenericCrudService], viewQueries: [{ propertyName: "formComp", first: true, predicate: PraxisDynamicForm, descendants: true }], ngImport: i0, template: `
5098
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: DynamicFormDialogHostComponent, isStandalone: true, selector: "praxis-dynamic-form-dialog-host", host: { properties: { "attr.data-density": "modal.density || \"default\"", "attr.data-presentation": "presentation", "class.praxis-drawer": "presentation === \"drawer\"" }, classAttribute: "praxis-dialog" }, providers: [GenericCrudService], viewQueries: [{ propertyName: "formComp", first: true, predicate: PraxisDynamicForm, descendants: true }], ngImport: i0, template: `
5036
5099
  <div mat-dialog-title class="dialog-header">
5037
5100
  <h2 id="crudDialogTitle" class="dialog-title">
5038
5101
  {{ data.action?.label || texts.title }}
@@ -5074,6 +5137,7 @@ class DynamicFormDialogHostComponent {
5074
5137
  [submitMethod]="submitMethod"
5075
5138
  [apiEndpointKey]="apiEndpointKey"
5076
5139
  [apiUrlEntry]="apiUrlEntry"
5140
+ [layoutPolicy]="layoutPolicy"
5077
5141
  [presentationModeGlobal]="mode === 'view' ? true : null"
5078
5142
  [backConfig]="backConfig"
5079
5143
  [actions]="formActions"
@@ -5081,7 +5145,7 @@ class DynamicFormDialogHostComponent {
5081
5145
  (formCancel)="onCancel()"
5082
5146
  ></praxis-dynamic-form>
5083
5147
  </mat-dialog-content>
5084
- `, isInline: true, styles: [":host{--dlg-header-h: 56px;--dlg-footer-h: 56px;--dlg-pad: 16px;display:flex;flex-direction:column;height:100%;overflow:hidden}:host([data-density=\"compact\"]){--dlg-header-h: 44px;--dlg-footer-h: 44px;--dlg-pad: 12px}.dialog-header{position:sticky;top:0;z-index:1;display:flex;align-items:center;gap:var(--dlg-pad);padding:0 var(--dlg-pad);height:var(--dlg-header-h);margin:0;background:var(--md-sys-color-surface-container-high);border-bottom:1px solid var(--md-sys-color-outline-variant);color:var(--md-sys-color-on-surface)}.dialog-title{margin:0;font:inherit;font-weight:600;color:var(--md-sys-color-on-surface)}.spacer{flex:1}.dialog-content{overflow:auto;padding:var(--dlg-pad);max-height:calc(100svh - var(--dlg-header-h) - 32px)}.dialog-header button.mat-icon-button{color:var(--md-sys-color-on-surface-variant)}.dialog-header button.mat-icon-button:hover{color:var(--md-sys-color-primary);background:var(--md-sys-color-primary-container)}.dialog-footer{position:sticky;bottom:0;z-index:1;padding:var(--dlg-pad)}\n"], dependencies: [{ kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i1.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i6.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "component", type: PraxisDynamicForm, selector: "praxis-dynamic-form", inputs: ["resourcePath", "resourceId", "initialValue", "editorialContext", "mode", "config", "actions", "schemaSource", "schemaUrl", "readUrl", "submitUrl", "submitMethod", "responseSchemaUrl", "apiEndpointKey", "apiUrlEntry", "enableCustomization", "showAiAssistant", "formId", "componentInstanceId", "configPersistenceStrategy", "layout", "backConfig", "hooks", "removeEmptyContainersOnSave", "reactiveValidation", "reactiveValidationDebounceMs", "notifyIfOutdated", "snoozeMs", "autoOpenSettingsOnOutdated", "readonlyModeGlobal", "disabledModeGlobal", "presentationModeGlobal", "visibleGlobal", "domainRules", "customEndpoints"], outputs: ["formSubmit", "formCancel", "formReset", "configChange", "configPatchChange", "formReady", "valueChange", "syncCompleted", "initializationError", "loadingStateChange", "enableCustomizationChange", "customAction", "actionConfirmation", "schemaStatusChange", "fieldRenderError", "ruleDiagnosticsChange"] }] });
5148
+ `, isInline: true, styles: ["praxis-dynamic-form-dialog-host{--dlg-header-h: 56px;--dlg-footer-h: 56px;--dlg-pad: 16px;display:flex;flex-direction:column;height:100%;overflow:hidden}praxis-dynamic-form-dialog-host[data-density=compact]{--dlg-header-h: 44px;--dlg-footer-h: 44px;--dlg-pad: 12px}praxis-dynamic-form-dialog-host .dialog-header{position:sticky;top:0;z-index:1;display:flex;align-items:center;gap:var(--dlg-pad);padding:0 var(--dlg-pad);height:var(--dlg-header-h);margin:0;background:var(--md-sys-color-surface-container-high);border-bottom:1px solid var(--md-sys-color-outline-variant);color:var(--md-sys-color-on-surface)}praxis-dynamic-form-dialog-host .dialog-title{margin:0;font:inherit;font-weight:600;color:var(--md-sys-color-on-surface)}praxis-dynamic-form-dialog-host .spacer{flex:1}praxis-dynamic-form-dialog-host .dialog-content{flex:1 1 auto;overflow:auto;padding:var(--dlg-pad);max-height:calc(100svh - var(--dlg-header-h) - 32px)}praxis-dynamic-form-dialog-host.praxis-drawer{--dlg-header-h: 64px;width:100%;min-width:0;max-width:100vw;height:100dvh;background:var(--pfx-form-surface, var(--md-sys-color-surface));color:var(--md-sys-color-on-surface)}praxis-dynamic-form-dialog-host.praxis-drawer .dialog-header{background:color-mix(in srgb,var(--md-sys-color-surface-container-high, var(--md-sys-color-surface)),transparent 4%)}praxis-dynamic-form-dialog-host.praxis-drawer .dialog-content{max-height:none;min-height:0;padding:clamp(12px,2.4vw,24px)}praxis-dynamic-form-dialog-host .dialog-header button.mat-icon-button{color:var(--md-sys-color-on-surface-variant)}praxis-dynamic-form-dialog-host .dialog-header button.mat-icon-button:hover{color:var(--md-sys-color-primary);background:var(--md-sys-color-primary-container)}praxis-dynamic-form-dialog-host .dialog-footer{position:sticky;bottom:0;z-index:1;padding:var(--dlg-pad)}.pfx-blur-backdrop{background-color:var(--pfx-backdrop, rgba(15, 23, 42, .42))!important;backdrop-filter:blur(var(--pfx-backdrop-blur, 10px)) saturate(110%);-webkit-backdrop-filter:blur(var(--pfx-backdrop-blur, 10px)) saturate(110%)}.pfx-transparent-backdrop{background-color:transparent!important}.cdk-overlay-pane.pfx-dialog-pane{overflow:hidden;transition:width .2s ease,height .2s ease,margin .2s ease}.cdk-overlay-pane.pfx-dialog-pane .mat-mdc-dialog-surface,.cdk-overlay-pane.pfx-dialog-pane .mdc-dialog__surface{display:flex;flex-direction:column;width:100%;height:100%;max-height:inherit;overflow:hidden;background:var(--pfx-form-surface, var(--md-sys-color-surface))!important;border:1px solid var(--pfx-form-stroke, var(--md-sys-color-outline-variant))!important}.cdk-overlay-pane.pfx-dialog-pane.pfx-dialog-frosted .mat-mdc-dialog-surface,.cdk-overlay-pane.pfx-dialog-pane.pfx-dialog-frosted .mdc-dialog__surface{backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px)}.cdk-overlay-pane.pfx-drawer-pane{margin:0!important;border-radius:0!important;box-shadow:var(--md-sys-elevation-level3, 0 24px 80px rgba(15, 23, 42, .28)),0 0 0 1px color-mix(in srgb,var(--md-sys-color-outline, #64748b) 24%,transparent)}.cdk-overlay-pane.pfx-drawer-pane .mat-mdc-dialog-surface,.cdk-overlay-pane.pfx-drawer-pane .mdc-dialog__surface{border-radius:0!important}\n"], dependencies: [{ kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i1.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i6.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "component", type: PraxisDynamicForm, selector: "praxis-dynamic-form", inputs: ["resourcePath", "resourceId", "initialValue", "editorialContext", "mode", "config", "actions", "schemaSource", "schemaUrl", "readUrl", "submitUrl", "submitMethod", "responseSchemaUrl", "apiEndpointKey", "apiUrlEntry", "enableCustomization", "showAiAssistant", "formId", "componentInstanceId", "configPersistenceStrategy", "layout", "generatedLayoutPreset", "layoutPolicy", "backConfig", "hooks", "removeEmptyContainersOnSave", "reactiveValidation", "reactiveValidationDebounceMs", "notifyIfOutdated", "snoozeMs", "autoOpenSettingsOnOutdated", "readonlyModeGlobal", "disabledModeGlobal", "presentationModeGlobal", "visibleGlobal", "fieldIconPolicy", "domainRules", "customEndpoints"], outputs: ["formSubmit", "formCancel", "formReset", "configChange", "configPatchChange", "formReady", "valueChange", "syncCompleted", "initializationError", "loadingStateChange", "enableCustomizationChange", "customAction", "actionConfirmation", "schemaStatusChange", "fieldRenderError", "ruleDiagnosticsChange"] }], encapsulation: i0.ViewEncapsulation.None });
5085
5149
  }
5086
5150
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DynamicFormDialogHostComponent, decorators: [{
5087
5151
  type: Component,
@@ -5091,9 +5155,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
5091
5155
  MatIconModule,
5092
5156
  PraxisIconDirective,
5093
5157
  PraxisDynamicForm
5094
- ], providers: [GenericCrudService], host: {
5158
+ ], encapsulation: ViewEncapsulation.None, providers: [GenericCrudService], host: {
5095
5159
  class: 'praxis-dialog',
5096
5160
  '[attr.data-density]': 'modal.density || "default"',
5161
+ '[attr.data-presentation]': 'presentation',
5162
+ '[class.praxis-drawer]': 'presentation === "drawer"',
5097
5163
  }, template: `
5098
5164
  <div mat-dialog-title class="dialog-header">
5099
5165
  <h2 id="crudDialogTitle" class="dialog-title">
@@ -5136,6 +5202,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
5136
5202
  [submitMethod]="submitMethod"
5137
5203
  [apiEndpointKey]="apiEndpointKey"
5138
5204
  [apiUrlEntry]="apiUrlEntry"
5205
+ [layoutPolicy]="layoutPolicy"
5139
5206
  [presentationModeGlobal]="mode === 'view' ? true : null"
5140
5207
  [backConfig]="backConfig"
5141
5208
  [actions]="formActions"
@@ -5143,7 +5210,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
5143
5210
  (formCancel)="onCancel()"
5144
5211
  ></praxis-dynamic-form>
5145
5212
  </mat-dialog-content>
5146
- `, styles: [":host{--dlg-header-h: 56px;--dlg-footer-h: 56px;--dlg-pad: 16px;display:flex;flex-direction:column;height:100%;overflow:hidden}:host([data-density=\"compact\"]){--dlg-header-h: 44px;--dlg-footer-h: 44px;--dlg-pad: 12px}.dialog-header{position:sticky;top:0;z-index:1;display:flex;align-items:center;gap:var(--dlg-pad);padding:0 var(--dlg-pad);height:var(--dlg-header-h);margin:0;background:var(--md-sys-color-surface-container-high);border-bottom:1px solid var(--md-sys-color-outline-variant);color:var(--md-sys-color-on-surface)}.dialog-title{margin:0;font:inherit;font-weight:600;color:var(--md-sys-color-on-surface)}.spacer{flex:1}.dialog-content{overflow:auto;padding:var(--dlg-pad);max-height:calc(100svh - var(--dlg-header-h) - 32px)}.dialog-header button.mat-icon-button{color:var(--md-sys-color-on-surface-variant)}.dialog-header button.mat-icon-button:hover{color:var(--md-sys-color-primary);background:var(--md-sys-color-primary-container)}.dialog-footer{position:sticky;bottom:0;z-index:1;padding:var(--dlg-pad)}\n"] }]
5213
+ `, styles: ["praxis-dynamic-form-dialog-host{--dlg-header-h: 56px;--dlg-footer-h: 56px;--dlg-pad: 16px;display:flex;flex-direction:column;height:100%;overflow:hidden}praxis-dynamic-form-dialog-host[data-density=compact]{--dlg-header-h: 44px;--dlg-footer-h: 44px;--dlg-pad: 12px}praxis-dynamic-form-dialog-host .dialog-header{position:sticky;top:0;z-index:1;display:flex;align-items:center;gap:var(--dlg-pad);padding:0 var(--dlg-pad);height:var(--dlg-header-h);margin:0;background:var(--md-sys-color-surface-container-high);border-bottom:1px solid var(--md-sys-color-outline-variant);color:var(--md-sys-color-on-surface)}praxis-dynamic-form-dialog-host .dialog-title{margin:0;font:inherit;font-weight:600;color:var(--md-sys-color-on-surface)}praxis-dynamic-form-dialog-host .spacer{flex:1}praxis-dynamic-form-dialog-host .dialog-content{flex:1 1 auto;overflow:auto;padding:var(--dlg-pad);max-height:calc(100svh - var(--dlg-header-h) - 32px)}praxis-dynamic-form-dialog-host.praxis-drawer{--dlg-header-h: 64px;width:100%;min-width:0;max-width:100vw;height:100dvh;background:var(--pfx-form-surface, var(--md-sys-color-surface));color:var(--md-sys-color-on-surface)}praxis-dynamic-form-dialog-host.praxis-drawer .dialog-header{background:color-mix(in srgb,var(--md-sys-color-surface-container-high, var(--md-sys-color-surface)),transparent 4%)}praxis-dynamic-form-dialog-host.praxis-drawer .dialog-content{max-height:none;min-height:0;padding:clamp(12px,2.4vw,24px)}praxis-dynamic-form-dialog-host .dialog-header button.mat-icon-button{color:var(--md-sys-color-on-surface-variant)}praxis-dynamic-form-dialog-host .dialog-header button.mat-icon-button:hover{color:var(--md-sys-color-primary);background:var(--md-sys-color-primary-container)}praxis-dynamic-form-dialog-host .dialog-footer{position:sticky;bottom:0;z-index:1;padding:var(--dlg-pad)}.pfx-blur-backdrop{background-color:var(--pfx-backdrop, rgba(15, 23, 42, .42))!important;backdrop-filter:blur(var(--pfx-backdrop-blur, 10px)) saturate(110%);-webkit-backdrop-filter:blur(var(--pfx-backdrop-blur, 10px)) saturate(110%)}.pfx-transparent-backdrop{background-color:transparent!important}.cdk-overlay-pane.pfx-dialog-pane{overflow:hidden;transition:width .2s ease,height .2s ease,margin .2s ease}.cdk-overlay-pane.pfx-dialog-pane .mat-mdc-dialog-surface,.cdk-overlay-pane.pfx-dialog-pane .mdc-dialog__surface{display:flex;flex-direction:column;width:100%;height:100%;max-height:inherit;overflow:hidden;background:var(--pfx-form-surface, var(--md-sys-color-surface))!important;border:1px solid var(--pfx-form-stroke, var(--md-sys-color-outline-variant))!important}.cdk-overlay-pane.pfx-dialog-pane.pfx-dialog-frosted .mat-mdc-dialog-surface,.cdk-overlay-pane.pfx-dialog-pane.pfx-dialog-frosted .mdc-dialog__surface{backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px)}.cdk-overlay-pane.pfx-drawer-pane{margin:0!important;border-radius:0!important;box-shadow:var(--md-sys-elevation-level3, 0 24px 80px rgba(15, 23, 42, .28)),0 0 0 1px color-mix(in srgb,var(--md-sys-color-outline, #64748b) 24%,transparent)}.cdk-overlay-pane.pfx-drawer-pane .mat-mdc-dialog-surface,.cdk-overlay-pane.pfx-drawer-pane .mdc-dialog__surface{border-radius:0!important}\n"] }]
5147
5214
  }], ctorParameters: () => [{ type: undefined, decorators: [{
5148
5215
  type: Inject,
5149
5216
  args: [MatDialogRef]
@@ -5699,6 +5766,7 @@ const CRUD_AI_CAPABILITIES = {
5699
5766
  { path: 'actions[].params[].to', category: 'actions', valueKind: 'enum', allowedValues: ENUMS.paramTarget, description: 'Destino do parametro.' },
5700
5767
  { path: 'actions[].params[].name', category: 'actions', valueKind: 'string', description: 'Nome do parametro no destino.' },
5701
5768
  { path: 'actions[].form.initialValue', category: 'actions', valueKind: 'object', description: 'Seed fixo do formulario injetado em inputs.initialValue antes da abertura.' },
5769
+ { path: 'actions[].form.layoutPolicy', category: 'actions', valueKind: 'object', description: 'Politica schema-driven opt-in encaminhada ao Dynamic Form para materializar detalhe ou command form sem FormConfig.sections local; deve acompanhar schemaUrl compativel, especialmente schemaType=request para comandos.' },
5702
5770
  { path: 'actions[].back', category: 'navigation', valueKind: 'object', description: 'BackConfig por acao.' },
5703
5771
  { path: 'actions[].back.strategy', category: 'navigation', valueKind: 'enum', allowedValues: ENUMS.backStrategy, description: 'Estrategia de retorno da acao (auto, close, navigate).' },
5704
5772
  { path: 'actions[].back.returnTo', category: 'navigation', valueKind: 'string', description: 'Rota ou destino usado quando a estrategia de retorno for navigate.' },
@@ -5736,6 +5804,7 @@ const surfaceConfigureSchema = {
5736
5804
  submitMethod: { enum: ['post', 'put', 'patch', 'delete'] },
5737
5805
  apiEndpointKey: { type: 'string' },
5738
5806
  initialValue: { type: 'object' },
5807
+ layoutPolicy: { type: 'object' },
5739
5808
  },
5740
5809
  },
5741
5810
  params: {
@@ -6017,14 +6086,14 @@ const PRAXIS_CRUD_AUTHORING_MANIFEST = {
6017
6086
  target: { kind: 'dialogHost', resolver: 'crud-dialog-host-defaults', ambiguityPolicy: 'fail', required: true },
6018
6087
  inputSchema: dialogHostSchema,
6019
6088
  effects: [{ kind: 'compile-domain-patch', handler: 'crud-dialog-host-set', handlerContract: {
6020
- reads: ['CrudMetadata.defaults', 'CrudLauncherService.resolveOpenMode', 'DialogService', 'CRUD_DRAWER_ADAPTER'],
6089
+ reads: ['CrudMetadata.defaults', 'CrudLauncherService.resolveOpenMode', 'DialogService', 'DynamicFormDialogHostComponent', 'CRUD_DRAWER_ADAPTER'],
6021
6090
  writes: ['CrudMetadata.defaults.openMode', 'CrudMetadata.defaults.modal', 'CrudMetadata.defaults.back'],
6022
6091
  identityKeys: ['crudId'],
6023
6092
  inputSchema: dialogHostSchema,
6024
- failureModes: ['open-mode-unsupported', 'drawer-adapter-missing', 'modal-size-invalid', 'back-policy-invalid'],
6025
- description: 'Configures CRUD-owned route/modal/drawer defaults consumed by the launcher and dialog host.',
6093
+ failureModes: ['open-mode-unsupported', 'drawer-runtime-unavailable', 'modal-size-invalid', 'back-policy-invalid'],
6094
+ description: 'Configures CRUD-owned route/modal/drawer defaults consumed by the launcher, default dialog-backed drawer runtime and optional host drawer adapter.',
6026
6095
  } }],
6027
- validators: ['open-mode-supported', 'modal-size-valid', 'drawer-adapter-available-when-needed', 'back-policy-valid', 'settings-panel-shell-compatible'],
6096
+ validators: ['open-mode-supported', 'modal-size-valid', 'drawer-runtime-available', 'back-policy-valid', 'settings-panel-shell-compatible'],
6028
6097
  affectedPaths: ['defaults.openMode', 'defaults.modal', 'defaults.back'],
6029
6098
  submissionImpact: 'config-only',
6030
6099
  preconditions: ['crud-metadata-loaded'],
@@ -6100,7 +6169,7 @@ const PRAXIS_CRUD_AUTHORING_MANIFEST = {
6100
6169
  { validatorId: 'permissions-delete-valid', level: 'error', code: 'CRUD_DELETE_PERMISSION_VALID', description: 'Delete permission cannot bypass resource capabilities or confirmation policy.' },
6101
6170
  { validatorId: 'open-mode-supported', level: 'error', code: 'CRUD_OPEN_MODE_SUPPORTED', description: 'Open mode must be route, modal or drawer.' },
6102
6171
  { validatorId: 'modal-size-valid', level: 'error', code: 'CRUD_MODAL_SIZE_VALID', description: 'Modal sizing defaults must be valid DialogConfig values.' },
6103
- { validatorId: 'drawer-adapter-available-when-needed', level: 'error', code: 'CRUD_DRAWER_ADAPTER_AVAILABLE', description: 'Drawer open mode requires a host-provided drawer adapter.' },
6172
+ { validatorId: 'drawer-runtime-available', level: 'error', code: 'CRUD_DRAWER_RUNTIME_AVAILABLE', description: 'Drawer open mode uses the default dialog-backed drawer runtime with CRUD-owned chrome, responsive right-panel sizing, Escape/backdrop handling and semantic close/save results; a host drawer adapter is optional only for shell-specific presentation.' },
6104
6173
  { validatorId: 'back-policy-valid', level: 'error', code: 'CRUD_BACK_POLICY_VALID', description: 'Back policy must be valid for route/modal/drawer behavior.' },
6105
6174
  { validatorId: 'settings-panel-shell-compatible', level: 'warning', code: 'CRUD_SETTINGS_PANEL_COMPATIBLE', description: 'Authoring shell must preserve apply/save/reset semantics.' },
6106
6175
  { validatorId: 'action-permission-supported', level: 'error', code: 'CRUD_ACTION_PERMISSION_SUPPORTED', description: 'Action permissions must map to supported resource capabilities.' },
package/package.json CHANGED
@@ -1,20 +1,20 @@
1
1
  {
2
2
  "name": "@praxisui/crud",
3
- "version": "9.0.0-beta.4",
3
+ "version": "9.0.0-beta.40",
4
4
  "description": "CRUD building blocks for Praxis UI: integrates dynamic forms and tables with unified configuration and services.",
5
5
  "peerDependencies": {
6
6
  "@angular/common": "^21.0.0",
7
7
  "@angular/core": "^21.0.0",
8
- "@praxisui/dynamic-form": "^9.0.0-beta.4",
9
- "@praxisui/table": "^9.0.0-beta.4",
10
- "@praxisui/core": "^9.0.0-beta.4",
11
- "@praxisui/dynamic-fields": "^9.0.0-beta.4",
12
- "@praxisui/settings-panel": "^9.0.0-beta.4",
8
+ "@praxisui/dynamic-form": "^9.0.0-beta.40",
9
+ "@praxisui/table": "^9.0.0-beta.40",
10
+ "@praxisui/core": "^9.0.0-beta.40",
11
+ "@praxisui/dynamic-fields": "^9.0.0-beta.40",
12
+ "@praxisui/settings-panel": "^9.0.0-beta.40",
13
13
  "@angular/cdk": "^21.0.0",
14
14
  "@angular/forms": "^21.0.0",
15
15
  "@angular/material": "^21.0.0",
16
16
  "@angular/router": "^21.0.0",
17
- "@praxisui/ai": "^9.0.0-beta.4",
17
+ "@praxisui/ai": "^9.0.0-beta.40",
18
18
  "rxjs": "~7.8.0"
19
19
  },
20
20
  "dependencies": {
@@ -28,6 +28,7 @@
28
28
  "keywords": [
29
29
  "angular",
30
30
  "praxisui",
31
+ "praxis",
31
32
  "crud",
32
33
  "admin",
33
34
  "backoffice",
@@ -48,7 +49,10 @@
48
49
  "./drawer-adapter": {
49
50
  "types": "./types/praxisui-crud-drawer-adapter.d.ts",
50
51
  "default": "./fesm2022/praxisui-crud-drawer-adapter.mjs"
52
+ },
53
+ "./ai/component-registry.json": {
54
+ "default": "./ai/component-registry.json"
51
55
  }
52
56
  },
53
57
  "type": "module"
54
- }
58
+ }
@@ -1,5 +1,5 @@
1
1
  import * as _praxisui_core from '@praxisui/core';
2
- import { RowAction, ToolbarAction, ApiEndpoint, ApiUrlEntry, BackConfig, TableConfig, PraxisDataQueryContext, FormConfig, ResourceActionCatalogItem, ResourceSurfaceCatalogItem, LoadingState, RestApiLinks, ResourceCapabilitySnapshot, GenericCrudService, AsyncConfigStorage, ComponentDocMeta, AiCapabilityCatalog, AiCapability, AiCapabilityCategory, AiValueKind, ComponentAuthoringManifest, SettingsValueProvider } from '@praxisui/core';
2
+ import { RowAction, ToolbarAction, ApiEndpoint, ApiUrlEntry, DynamicFormLayoutPolicy, BackConfig, TableConfig, PraxisDataQueryContext, FormConfig, ResourceActionCatalogItem, ResourceSurfaceCatalogItem, LoadingState, RestApiLinks, ResourceCapabilitySnapshot, GenericCrudService, AsyncConfigStorage, ComponentDocMeta, AiCapabilityCatalog, AiCapability, AiCapabilityCategory, AiValueKind, ComponentAuthoringManifest, SettingsValueProvider } from '@praxisui/core';
3
3
  export { BackConfig } from '@praxisui/core';
4
4
  import * as _angular_core from '@angular/core';
5
5
  import { NgZone, OnChanges, EventEmitter, SimpleChanges, OnInit, Provider, AfterViewInit, OnDestroy } from '@angular/core';
@@ -53,6 +53,7 @@ interface CrudActionFormContract {
53
53
  apiEndpointKey?: ApiEndpoint | string | null;
54
54
  apiUrlEntry?: ApiUrlEntry | null;
55
55
  initialValue?: Record<string, unknown> | null;
56
+ layoutPolicy?: DynamicFormLayoutPolicy | null;
56
57
  }
57
58
  type CrudActionResolutionMode = 'inferred' | 'explicit';
58
59
  type CrudAction = (RowAction | ToolbarAction) & {
@@ -316,6 +317,7 @@ declare class CrudLauncherService {
316
317
  submitMethod?: string | null;
317
318
  apiEndpointKey?: unknown;
318
319
  apiUrlEntry?: unknown;
320
+ layoutPolicy?: unknown;
319
321
  };
320
322
  private buildInferredFormId;
321
323
  private isCanonicalCrudAction;
@@ -333,6 +335,7 @@ declare class DynamicFormDialogHostComponent implements OnInit {
333
335
  private configStorage;
334
336
  formComp?: PraxisDynamicForm;
335
337
  modal: any;
338
+ presentation: 'modal' | 'drawer';
336
339
  maximized: boolean;
337
340
  private initialSize;
338
341
  private rememberState;
@@ -347,6 +350,7 @@ declare class DynamicFormDialogHostComponent implements OnInit {
347
350
  submitMethod?: string | null;
348
351
  apiEndpointKey?: ApiEndpoint | string | null;
349
352
  apiUrlEntry?: ApiUrlEntry | null;
353
+ layoutPolicy?: DynamicFormLayoutPolicy | null;
350
354
  formActions?: FormConfig['actions'];
351
355
  mode: 'create' | 'edit' | 'view';
352
356
  backConfig?: BackConfig;
@@ -355,6 +359,7 @@ declare class DynamicFormDialogHostComponent implements OnInit {
355
359
  constructor(dialogRef: DialogRef<DynamicFormDialogHostComponent>, data: any, dialogService: DialogService, crud: GenericCrudService<any>, configStorage: AsyncConfigStorage);
356
360
  private extractInitialValue;
357
361
  private resolveFormActions;
362
+ private resolveLayoutPolicy;
358
363
  private resolveSubmitLabel;
359
364
  ngOnInit(): void;
360
365
  onSave(result: unknown): void;