@praxisui/crud 9.0.0-beta.31 → 9.0.0-beta.32

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,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": "1.0.0",
3
- "generatedAt": "2026-07-02T21:34:12.637Z",
3
+ "generatedAt": "2026-07-02T23:12:01.271Z",
4
4
  "packageName": "@praxisui/crud",
5
- "packageVersion": "9.0.0-beta.31",
5
+ "packageVersion": "9.0.0-beta.32",
6
6
  "sourceRegistry": "praxis-component-registry-ingestion",
7
7
  "sourceRegistryVersion": "1.0.0",
8
8
  "componentCount": 2,
@@ -2385,7 +2385,7 @@
2385
2385
  "validatorId": "drawer-runtime-available",
2386
2386
  "level": "error",
2387
2387
  "code": "CRUD_DRAWER_RUNTIME_AVAILABLE",
2388
- "description": "Drawer open mode uses the default dialog-backed drawer runtime; a host drawer adapter is optional for shell-specific presentation."
2388
+ "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."
2389
2389
  },
2390
2390
  {
2391
2391
  "validatorId": "back-policy-valid",
@@ -2677,9 +2677,9 @@
2677
2677
  {
2678
2678
  "chunkIndex": 2,
2679
2679
  "chunkKind": "authoring_manifest",
2680
- "content": "{\n \"schemaVersion\": \"1.0.0\",\n \"componentId\": \"praxis-crud\",\n \"ownerPackage\": \"@praxisui/crud\",\n \"configSchemaId\": \"CrudMetadata\",\n \"manifestVersion\": \"1.0.0\",\n \"runtimeInputs\": [\n {\n \"name\": \"metadata\",\n \"type\": \"CrudMetadata | string\",\n \"description\": \"Canonical CRUD metadata or serialized metadata document.\"\n },\n {\n \"name\": \"crudId\",\n \"type\": \"string\",\n \"description\": \"Stable CRUD instance id used for table/form identity and persistence.\"\n },\n {\n \"name\": \"componentInstanceId\",\n \"type\": \"string\",\n \"description\": \"Optional stable host instance id for multiple CRUD widgets on the same route.\"\n },\n {\n \"name\": \"context\",\n \"type\": \"Record<string, unknown>\",\n \"description\": \"Opaque host context used for authoring seeds and launcher inputs.\"\n },\n {\n \"name\": \"afterOpen\",\n \"type\": \"{ mode: FormOpenMode; action: string }\",\n \"description\": \"Emitted after a CRUD action opens.\"\n },\n {\n \"name\": \"afterSave\",\n \"type\": \"{ id: string | number; data: unknown }\",\n \"description\": \"Emitted after save; CRUD refetches the list.\"\n },\n {\n \"name\": \"afterDelete\",\n \"type\": \"{ id: string | number }\",\n \"description\": \"Emitted after delete; CRUD refetches the list.\"\n }\n ],\n \"editableTargets\": [\n {\n \"kind\": \"resourceBinding\",\n \"resolver\": \"crud-resource-by-path-or-key\",\n \"description\": \"Resource path/key, id field, endpoint key and query context owned by CRUD orchestration.\"\n },\n {\n \"kind\": \"listSurface\",\n \"resolver\": \"crud-list-surface\",\n \"description\": \"CRUD-hosted list surface and table delegation boundary.\"\n },\n {\n \"kind\": \"createSurface\",\n \"resolver\": \"crud-action-by-id:create\",\n \"description\": \"Create action open mode, route/form binding and launcher inputs.\"\n },\n {\n \"kind\": \"editSurface\",\n \"resolver\": \"crud-action-by-id:edit\",\n \"description\": \"Edit action open mode, route/form binding and launcher inputs.\"\n },\n {\n \"kind\": \"viewSurface\",\n \"resolver\": \"crud-action-by-id:view\",\n \"description\": \"View action open mode, route/form binding and launcher inputs.\"\n },\n {\n \"kind\": \"deleteBehavior\",\n \"resolver\": \"crud-action-by-id:delete\",\n \"description\": \"Delete action enablement, confirmation, endpoint and capability policy.\"\n },\n {\n \"kind\": \"dialogHost\",\n \"resolver\": \"crud-dialog-host-defaults\",\n \"description\": \"Route/modal/drawer defaults consumed by CrudLauncherService and DynamicFormDialogHostComponent.\"\n },\n {\n \"kind\": \"formBinding\",\n \"resolver\": \"crud-action-form-contract-by-action-id\",\n \"description\": \"CRUD-owned form binding fields: formId, schemaUrl, submitUrl, submitMethod, params and initialValue.\"\n },\n {\n \"kind\": \"permissions\",\n \"resolver\": \"crud-resource-capabilities\",\n \"description\": \"CRUD action availability derived from resource capabilities and action permissions.\"\n },\n {\n \"kind\": \"domainGovernanceContext\",\n \"resolver\": \"domain-catalog-context-by-resource-key\",\n \"description\": \"Read-only semantic/governance context resolved from Domain Catalog and referenced from CRUD queryContext.meta.\"\n },\n {\n \"kind\": \"childOperation\",\n \"resolver\": \"child-authoring-manifest-operation\",\n \"description\": \"Delegated form/table/dialog/settings-panel operation owned by the child component manifest.\"\n }\n ],\n \"operations\": [\n {\n \"operationId\": \"resource.bind\",\n \"title\": \"Bind CRUD resource\",\n \"scope\": \"dataBinding\",\n \"targetKind\": \"resourceBinding\",\n \"target\": {\n \"kind\": \"resourceBinding\",\n \"resolver\": \"crud-resource-by-path-or-key\",\n \"ambiguityPolicy\": \"fail\",\n \"required\": true\n },\n \"inputSchema\": {\n \"type\": \"object\",\n \"required\": [\n \"resourcePath\"\n ],\n \"properties\": {\n \"resourcePath\": {\n \"type\": \"string\"\n },\n \"resourceKey\": {\n \"type\": \"string\"\n },\n \"idField\": {\n \"type\": [\n \"string\",\n \"number\"\n ]\n },\n \"endpointKey\": {\n \"type\": \"string\"\n },\n \"queryContext\": {\n \"type\": \"object\"\n }\n }\n },\n \"effects\": [\n {\n \"kind\": \"compile-domain-patch\",\n \"handler\": \"crud-resource-bind\",\n \"handlerContract\": {\n \"reads\": [\n \"CrudMetadata.resource\",\n \"api_metadata\",\n \"ResourceDiscoveryService\",\n \"GET /{resource}/capabilities\"\n ],\n \"writes\": [\n \"CrudMetadata.resource\",\n \"CrudMetadata.queryContext\",\n \"PraxisCrudComponent.tableCrudContext\"\n ],\n \"identityKeys\": [\n \"resourcePath\",\n \"resourceKey\"\n ],\n \"failureModes\": [\n \"resource-not-found\",\n \"schema-url-not-canonical\",\n \"capabilities-unavailable\",\n \"id-field-missing\"\n ],\n \"description\": \"Binds CRUD to a canonical resource and validates it against api_metadata/resource capabilities before runtime use.\"\n }\n }\n ],\n \"validators\": [\n \"resource-exists-in-api-metadata\",\n \"resource-path-canonical\",\n \"resource-key-stable\",\n \"id-field-known\",\n \"resource-capabilities-resolvable\"\n ],\n \"affectedPaths\": [\n \"resource.path\",\n \"resource.idField\",\n \"resource.endpointKey\",\n \"queryContext\",\n \"filterCriteria\"\n ],\n \"submissionImpact\": \"affects-remote-binding\",\n \"preconditions\": [\n \"crud-metadata-loaded\",\n \"api-metadata-available\"\n ]\n },\n {\n \"operationId\": \"domain.governanceContext.attach\",\n \"title\": \"Attach Domain Catalog governance context\",\n \"scope\": \"dataBinding\",\n \"targetKind\": \"domainGovernanceContext\",\n \"target\": {\n \"kind\": \"domainGovernanceContext\",\n \"resolver\": \"domain-catalog-context-by-resource-key\",\n \"ambiguityPolicy\": \"fail\",\n \"required\": true\n },\n \"inputSchema\": {\n \"type\": \"object\",\n \"required\": [\n \"resourceKey\",\n \"query\"\n ],\n \"properties\": {\n \"resourceKey\": {\n \"type\": \"string\"\n },\n \"releaseId\": {\n \"type\": \"string\"\n },\n \"query\": {\n \"type\": \"string\"\n },\n \"itemTypes\": {\n \"type\": \"array\",\n \"items\": {\n \"enum\": [\n \"governance\",\n \"vocabulary\",\n \"relationship\"\n ]\n }\n },\n \"intent\": {\n \"enum\": [\n \"authoring\",\n \"explain\",\n \"validate\",\n \"ai-access-control\"\n ]\n }\n }\n },\n \"effects\": [\n {\n \"kind\": \"compile-domain-patch\",\n \"handler\": \"crud-domain-governance-context-attach\",\n \"handlerContract\": {\n \"reads\": [\n \"CrudMetadata.resource\",\n \"CrudMetadata.queryContext\",\n \"DomainCatalogService.getGovernanceContext\",\n \"DOMAIN_CATALOG_COMPONENT_CONTEXT_PACK\",\n \"api_metadata\"\n ],\n \"writes\": [\n \"CrudMetadata.queryContext.meta.domainCatalog\"\n ],\n \"identityKeys\": [\n \"resourceKey\",\n \"releaseId\",\n \"query\"\n ],\n \"failureModes\": [\n \"resource-key-missing\",\n \"domain-catalog-release-not-found\",\n \"governance-context-empty\",\n \"ai-usage-forbidden\"\n ],\n \"description\": \"Resolves read-only domain vocabulary/governance context and stores only a lightweight reference/probe under queryContext.meta.domainCatalog.\"\n }\n }\n ],\n \"validators\": [\n \"resource-key-stable\",\n \"domain-catalog-context-resolvable\",\n \"domain-catalog-read-only\",\n \"ai-usage-visibility-respected\",\n \"no-form-config-rule-materialization\"\n ],\n \"affectedPaths\": [\n \"queryContext.meta.domainCatalog\"\n ],\n \"submissionImpact\": \"config-only\",\n \"preconditions\": [\n \"crud-metadata-loaded\",\n \"api-metadata-available\",\n \"domain-catalog-service-available\"\n ]\n },\n {\n \"operationId\": \"list.surface.configure\",\n \"title\": \"Configure CRUD list surface\",\n \"scope\": \"interaction\",\n \"targetKind\": \"listSurface\",\n \"target\": {\n \"kind\": \"listSurface\",\n \"resolver\": \"crud-list-surface\",\n \"ambiguityPolicy\": \"fail\",\n \"required\": true\n },\n \"inputSchema\": {\n \"type\": \"object\",\n \"properties\": {\n \"tablePatch\": {\n \"type\": \"object\"\n },\n \"queryContext\": {\n \"type\": \"object\"\n },\n \"filterCriteria\": {\n \"type\": \"object\"\n }\n }\n },\n \"effects\": [\n {\n \"kind\": \"compile-domain-patch\",\n \"handler\": \"crud-list-surface-configure\",\n \"handlerContract\": {\n \"reads\": [\n \"CrudMetadata.table\",\n \"CrudMetadata.queryContext\",\n \"PRAXIS_TABLE_AUTHORING_MANIFEST\",\n \"CRUD_AI_CAPABILITIES\"\n ],\n \"writes\": [\n \"CrudMetadata.table\",\n \"CrudMetadata.queryContext\",\n \"CrudMetadata.filterCriteria\"\n ],\n \"identityKeys\": [\n \"crudId\"\n ],\n \"failureModes\": [\n \"table-operation-not-delegated\",\n \"table-patch-not-supported\",\n \"query-context-invalid\"\n ],\n \"description\": \"Configures CRUD-owned list orchestration while routing table semantics to the praxis-table manifest.\"\n }\n }\n ],\n \"validators\": [\n \"table-child-operation-delegated\",\n \"query-context-valid\",\n \"filter-criteria-bridge-valid\",\n \"crud-context-stable\"\n ],\n \"affectedPaths\": [\n \"table\",\n \"queryContext\",\n \"filterCriteria\"\n ],\n \"submissionImpact\": \"config-only\",\n \"preconditions\": [\n \"crud-metadata-loaded\",\n \"praxis-table-manifest-available\"\n ]\n },\n {\n \"operationId\": \"surface.create.configure\",\n \"title\": \"Configure create surface\",\n \"scope\": \"interaction\",\n \"targetKind\": \"createSurface\",\n \"target\": {\n \"kind\": \"createSurface\",\n \"resolver\": \"crud-action-by-id:create\",\n \"ambiguityPolicy\": \"fail\",\n \"required\": true\n },\n \"inputSchema\": {\n \"type\": \"object\",\n \"required\": [\n \"actionId\",\n \"openMode\"\n ],\n \"properties\": {\n \"actionId\": {\n \"enum\": [\n \"create\",\n \"edit\",\n \"view\"\n ]\n },\n \"openMode\": {\n \"enum\": [\n \"route\",\n \"modal\",\n \"drawer\"\n ]\n },\n \"route\": {\n \"type\": \"string\"\n },\n \"formId\": {\n \"type\": \"string\"\n },\n \"form\": {\n \"type\": \"object\",\n \"properties\": {\n \"schemaUrl\": {\n \"type\": \"string\"\n },\n \"submitUrl\": {\n \"type\": \"string\"\n },\n \"submitMethod\": {\n \"enum\": [\n \"post\",\n \"put\",\n \"patch\",\n \"delete\"\n ]\n },\n \"apiEndpointKey\": {\n \"type\": \"string\"\n },\n \"initialValue\": {\n \"type\": \"object\"\n },\n \"layoutPolicy\": {\n \"type\": \"object\"\n }\n }\n },\n \"params\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"object\",\n \"required\": [\n \"from\",\n \"to\",\n \"name\"\n ],\n \"properties\": {\n \"from\": {\n \"type\": \"string\"\n },\n \"to\": {\n \"enum\": [\n \"routeParam\",\n \"query\",\n \"input\"\n ]\n },\n \"name\": {\n \"type\": \"string\"\n }\n }\n }\n },\n \"back\": {\n \"type\": \"object\"\n }\n }\n },\n \"effects\": [\n {\n \"kind\": \"compile-domain-patch\",\n \"handler\": \"crud-create-surface-configure\",\n \"handlerContract\": {\n \"reads\": [\n \"CrudMetadata.actions\",\n \"CrudLauncherService.resolveOpenMode\",\n \"DynamicFormDialogHostComponent\",\n \"api_metadata\"\n ],\n \"writes\": [\n \"CrudMetadata.actions[]\",\n \"CrudMetadata.actions[].form\",\n \"CrudMetadata.actions[].params\",\n \"CrudMetadata.actions[].back\"\n ],\n \"identityKeys\": [\n \"actionId\"\n ],\n \"failureModes\": [\n \"action-not-found\",\n \"open-mode-binding-incomplete\",\n \"schema-url-not-canonical\",\n \"submit-url-not-canonical\",\n \"resource-create-not-supported\"\n ],\n \"description\": \"Configures create action binding and launcher inputs without editing the child FormConfig.\"\n }\n }\n ],\n \"validators\": [\n \"action-exists\",\n \"open-mode-binding-complete\",\n \"schema-url-canonical\",\n \"submit-url-canonical\",\n \"resource-create-supported\",\n \"form-child-operation-delegated\"\n ],\n \"affectedPaths\": [\n \"actions[].openMode\",\n \"actions[].route\",\n \"actions[].formId\",\n \"actions[].form\",\n \"actions[].params\",\n \"actions[].back\"\n ],\n \"submissionImpact\": \"affects-schema-backed-data\",\n \"preconditions\": [\n \"crud-metadata-loaded\",\n \"resource-capabilities-resolved\"\n ]\n },\n {\n \"operationId\": \"surface.edit.configure\",\n \"title\": \"Configure edit surface\",\n \"scope\": \"interaction\",\n \"targetKind\": \"editSurface\",\n \"target\": {\n \"kind\": \"editSurface\",\n \"resolver\": \"crud-action-by-id:edit\",\n \"ambiguityPolicy\": \"fail\",\n \"required\": true\n },\n \"effects\": [\n {\n \"kind\": \"compile-domain-patch\",\n \"handler\": \"crud-edit-surface-configure\",\n \"handlerContract\": {\n \"reads\": [\n \"CrudMetadata.actions\",\n \"CrudMetadata.resource.idField\",\n \"CrudLauncherService.resolveOpenMode\",\n \"api_metadata\"\n ],\n \"writes\": [\n \"CrudMetadata.actions[]\",\n \"CrudMetadata.actions[].form\",\n \"CrudMetadata.actions[].params\",\n \"CrudMetadata.actions[].back\"\n ],\n \"identityKeys\": [\n \"actionId\"\n ],\n \"failureModes\": [\n \"action-not-found\",\n \"id-param-missing\",\n \"open-mode-binding-incomplete\",\n \"resource-edit-not-supported\",\n \"submit-url-not-canonical\"\n ],\n \"description\": \"Configures edit action routing/form binding and ensures id parameter mapping is available to the launcher.\"\n }\n }\n ],\n \"validators\": [\n \"action-exists\",\n \"id-field-known\",\n \"id-param-mapping-valid\",\n \"open-mode-binding-complete\",\n \"schema-url-canonical\",\n \"submit-url-canonical\",\n \"resource-edit-supported\",\n \"form-child-operation-delegated\"\n ],\n \"affectedPaths\": [\n \"actions[].openMode\",\n \"actions[].route\",\n \"actions[].formId\",\n \"actions[].form\",\n \"actions[].params\",\n \"actions[].back\"\n ],\n \"submissionImpact\": \"affects-schema-backed-data\",\n \"preconditions\": [\n \"crud-metadata-loaded\",\n \"resource-capabilities-resolved\"\n ]\n },\n {\n \"operationId\": \"surface.view.configure\",\n \"title\": \"Configure view surface\",\n \"scope\": \"interaction\",\n \"targetKind\": \"viewSurface\",\n \"target\": {\n \"kind\": \"viewSurface\",\n \"resolver\": \"crud-action-by-id:view\",\n \"ambiguityPolicy\": \"fail\",\n \"required\": true\n },\n \"effects\": [\n {\n \"kind\": \"compile-domain-patch\",\n \"handler\": \"crud-view-surface-configure\",\n \"handlerContract\": {\n \"reads\": [\n \"CrudMetadata.actions\",\n \"CrudLauncherService.resolveOpenMode\",\n \"DynamicFormDialogHostComponent\",\n \"api_metadata\"\n ],\n \"writes\": [\n \"CrudMetadata.actions[]\",\n \"CrudMetadata.actions[].form\",\n \"CrudMetadata.actions[].params\",\n \"CrudMetadata.actions[].back\"\n ],\n \"identityKeys\": [\n \"actionId\"\n ],\n \"failureModes\": [\n \"action-not-found\",\n \"open-mode-binding-incomplete\",\n \"resource-view-not-supported\",\n \"readonly-form-delegation-missing\"\n ],\n \"description\": \"Configures view action binding and delegates readonly form behavior to the dynamic-form manifest.\"\n }\n }\n ],\n \"validators\": [\n \"action-exists\",\n \"open-mode-binding-complete\",\n \"schema-url-canonical\",\n \"resource-view-supported\",\n \"form-child-operation-delegated\",\n \"readonly-form-delegation-valid\"\n ],\n \"affectedPaths\": [\n \"actions[].openMode\",\n \"actions[].route\",\n \"actions[].formId\",\n \"actions[].form\",\n \"actions[].params\",\n \"actions[].back\"\n ],\n \"submissionImpact\": \"config-only\",\n \"preconditions\": [\n \"crud-metadata-loaded\",\n \"resource-capabilities-resolved\"\n ]\n },\n {\n \"operationId\": \"delete.enabled.set\",\n \"title\": \"Configure delete behavior\",\n \"scope\": \"interaction\",\n \"targetKind\": \"deleteBehavior\",\n \"target\": {\n \"kind\": \"deleteBehavior\",\n \"resolver\": \"crud-action-by-id:delete\",\n \"ambiguityPolicy\": \"fail\",\n \"required\": true\n },\n \"inputSchema\": {\n \"type\": \"object\",\n \"required\": [\n \"enabled\"\n ],\n \"properties\": {\n \"enabled\": {\n \"type\": \"boolean\"\n },\n \"actionId\": {\n \"type\": \"string\"\n },\n \"requiresConfirmation\": {\n \"type\": \"boolean\"\n },\n \"autoDelete\": {\n \"type\": \"boolean\"\n },\n \"form\": {\n \"type\": \"object\",\n \"properties\": {\n \"submitUrl\": {\n \"type\": \"string\"\n },\n \"submitMethod\": {\n \"enum\": [\n \"delete\"\n ]\n },\n \"apiEndpointKey\": {\n \"type\": \"string\"\n }\n }\n }\n }\n },\n \"effects\": [\n {\n \"kind\": \"compile-domain-patch\",\n \"handler\": \"crud-delete-behavior-set\",\n \"handlerContract\": {\n \"reads\": [\n \"CrudMetadata.actions\",\n \"CrudMetadata.resource\",\n \"GET /{resource}/{id}/capabilities\"\n ],\n \"writes\": [\n \"CrudMetadata.actions[]\",\n \"CrudMetadata.actions[].requiresConfirmation\",\n \"CrudMetadata.actions[].autoDelete\",\n \"CrudMetadata.actions[].form\"\n ],\n \"identityKeys\": [\n \"actionId\"\n ],\n \"failureModes\": [\n \"delete-action-not-found\",\n \"resource-delete-not-supported\",\n \"destructive-delete-not-confirmed\",\n \"delete-submit-url-not-canonical\"\n ],\n \"description\": \"Enables or disables delete behavior with capability checks and explicit confirmation for destructive changes.\"\n }\n }\n ],\n \"destructive\": true,\n \"requiresConfirmation\": true,\n \"validators\": [\n \"delete-action-exists\",\n \"resource-delete-supported\",\n \"destructive-delete-confirmed\",\n \"submit-url-canonical\",\n \"permissions-delete-valid\"\n ],\n \"affectedPaths\": [\n \"actions[].disabled\",\n \"actions[].requiresConfirmation\",\n \"actions[].autoDelete\",\n \"actions[].form\",\n \"actions[].form.submitUrl\",\n \"actions[].form.submitMethod\",\n \"actions[].form.apiEndpointKey\"\n ],\n \"submissionImpact\": \"affects-schema-backed-data\",\n \"preconditions\": [\n \"crud-metadata-loaded\",\n \"resource-capabilities-resolved\",\n \"explicit-confirmation-provided\"\n ]\n },\n {\n \"operationId\": \"dialog.size.set\",\n \"title\": \"Configure CRUD dialog host defaults\",\n \"scope\": \"interaction\",\n \"targetKind\": \"dialogHost\",\n \"target\": {\n \"kind\": \"dialogHost\",\n \"resolver\": \"crud-dialog-host-defaults\",\n \"ambiguityPolicy\": \"fail\",\n \"required\": true\n },\n \"inputSchema\": {\n \"type\": \"object\",\n \"properties\": {\n \"defaultOpenMode\": {\n \"enum\": [\n \"route\",\n \"modal\",\n \"drawer\"\n ]\n },\n \"modal\": {\n \"type\": \"object\",\n \"properties\": {\n \"width\": {\n \"type\": \"string\"\n },\n \"height\": {\n \"type\": \"string\"\n },\n \"minWidth\": {\n \"type\": \"string\"\n },\n \"maxWidth\": {\n \"type\": \"string\"\n },\n \"density\": {\n \"type\": \"string\"\n },\n \"canMaximize\": {\n \"type\": \"boolean\"\n },\n \"rememberLastState\": {\n \"type\": \"boolean\"\n },\n \"startMaximized\": {\n \"type\": \"boolean\"\n },\n \"disableCloseOnEsc\": {\n \"type\": \"boolean\"\n },\n \"disableCloseOnBackdrop\": {\n \"type\": \"boolean\"\n },\n \"fullscreenBreakpoint\": {\n \"type\": \"string\"\n }\n }\n },\n \"back\": {\n \"type\": \"object\"\n }\n }\n },\n \"effects\": [\n {\n \"kind\": \"compile-domain-patch\",\n \"handler\": \"crud-dialog-host-set\",\n \"handlerContract\": {\n \"reads\": [\n \"CrudMetadata.defaults\",\n \"CrudLauncherService.resolveOpenMode\",\n \"DialogService\",\n \"DynamicFormDialogHostComponent\",\n \"CRUD_DRAWER_ADAPTER\"\n ],\n \"writes\": [\n \"CrudMetadata.defaults.openMode\",\n \"CrudMetadata.defaults.modal\",\n \"CrudMetadata.defaults.back\"\n ],\n \"identityKeys\": [\n \"crudId\"\n ],\n \"failureModes\": [\n \"open-mode-unsupported\",\n \"drawer-runtime-unavailable\",\n \"modal-size-invalid\",\n \"back-policy-invalid\"\n ],\n \"description\": \"Configures CRUD-owned route/modal/drawer defaults consumed by the launcher, default dialog-backed drawer runtime and optional host drawer adapter.\"\n }\n }\n ],\n \"validators\": [\n \"open-mode-supported\",\n \"modal-size-valid\",\n \"drawer-runtime-available\",\n \"back-policy-valid\",\n \"settings-panel-shell-compatible\"\n ],\n \"affectedPaths\": [\n \"defaults.openMode\",\n \"defaults.modal\",\n \"defaults.back\"\n ],\n \"submissionImpact\": \"config-only\",\n \"preconditions\": [\n \"crud-metadata-loaded\"\n ]\n },\n {\n \"operationId\": \"permissions.set\",\n \"title\": \"Configure CRUD permissions\",\n \"scope\": \"interaction\",\n \"targetKind\": \"permissions\",\n \"target\": {\n \"kind\": \"permissions\",\n \"resolver\": \"crud-resource-capabilities\",\n \"ambiguityPolicy\": \"fail\",\n \"required\": true\n },\n \"inputSchema\": {\n \"type\": \"object\",\n \"properties\": {\n \"requiredCapabilities\": {\n \"type\": \"array\",\n \"items\": {\n \"enum\": [\n \"create\",\n \"view\",\n \"edit\",\n \"delete\"\n ]\n }\n },\n \"actionPermissions\": {\n \"type\": \"object\"\n },\n \"denyWhenMissingCapability\": {\n \"type\": \"boolean\"\n }\n }\n },\n \"effects\": [\n {\n \"kind\": \"compile-domain-patch\",\n \"handler\": \"crud-permissions-set\",\n \"handlerContract\": {\n \"reads\": [\n \"GET /{resource}/capabilities\",\n \"GET /{resource}/{id}/capabilities\",\n \"CrudMetadata.actions\"\n ],\n \"writes\": [\n \"CrudMetadata.actions[].disabled\",\n \"CrudMetadata.actions[].visibleWhen\",\n \"CrudMetadata.actions[].requiresConfirmation\"\n ],\n \"identityKeys\": [\n \"resourcePath\"\n ],\n \"failureModes\": [\n \"capability-not-found\",\n \"action-permission-conflict\",\n \"delete-permission-without-confirmation\"\n ],\n \"description\": \"Aligns CRUD action visibility/disablement with resource capabilities without inventing a second permission source.\"\n }\n }\n ],\n \"validators\": [\n \"resource-capabilities-resolvable\",\n \"action-permission-supported\",\n \"delete-permission-requires-confirmation\",\n \"permissions-do-not-shadow-backend\"\n ],\n \"affectedPaths\": [\n \"actions[].disabled\",\n \"actions[].visibleWhen\",\n \"actions[].requiresConfirmation\"\n ],\n \"submissionImpact\": \"config-only\",\n \"preconditions\": [\n \"crud-metadata-loaded\",\n \"resource-capabilities-resolved\"\n ]\n },\n {\n \"operationId\": \"form.childOperation.delegate\",\n \"title\": \"Delegate child form/table/dialog authoring operation\",\n \"scope\": \"global\",\n \"targetKind\": \"childOperation\",\n \"target\": {\n \"kind\": \"childOperation\",\n \"resolver\": \"child-authoring-manifest-operation\",\n \"ambiguityPolicy\": \"fail\",\n \"required\": false\n },\n \"inputSchema\": {\n \"type\": \"object\",\n \"required\": [\n \"childComponentId\",\n \"childOperationId\",\n \"reason\"\n ],\n \"properties\": {\n \"childComponentId\": {\n \"enum\": [\n \"praxis-dynamic-form\",\n \"praxis-table\",\n \"praxis-dialog\",\n \"praxis-settings-panel\"\n ]\n },\n \"childOperationId\": {\n \"type\": \"string\"\n },\n \"reason\": {\n \"type\": \"string\"\n },\n \"childTarget\": {\n \"type\": \"object\"\n },\n \"childParams\": {\n \"type\": \"object\"\n }\n }\n },\n \"effects\": [\n {\n \"kind\": \"compile-domain-patch\",\n \"handler\": \"crud-child-operation-delegate\",\n \"handlerContract\": {\n \"reads\": [\n \"PRAXIS_DYNAMIC_FORM_AUTHORING_MANIFEST\",\n \"PRAXIS_TABLE_AUTHORING_MANIFEST\",\n \"PRAXIS_DIALOG_AUTHORING_MANIFEST\",\n \"PRAXIS_SETTINGS_PANEL_AUTHORING_MANIFEST\"\n ],\n \"writes\": [\n \"delegatedAuthoringOperations[]\"\n ],\n \"identityKeys\": [\n \"childComponentId\",\n \"childOperationId\"\n ],\n \"failureModes\": [\n \"child-manifest-missing\",\n \"child-operation-not-found\",\n \"attempted-local-child-config-write\"\n ],\n \"description\": \"Records explicit delegation when requested edits belong to child manifests instead of CRUD orchestration.\"\n }\n }\n ],\n \"validators\": [\n \"child-manifest-available\",\n \"child-operation-known\",\n \"no-local-form-config-write\",\n \"no-local-table-config-write\",\n \"delegation-target-valid\"\n ],\n \"affectedPaths\": [\n \"delegatedAuthoringOperations\"\n ],\n \"submissionImpact\": \"none\",\n \"preconditions\": [\n \"child-manifest-available\"\n ]\n }\n ],\n \"validators\": [\n {\n \"validatorId\": \"resource-exists-in-api-metadata\",\n \"level\": \"error\",\n \"code\": \"CRUD_RESOURCE_EXISTS\",\n \"description\": \"Resource must exist in api_metadata or resource discovery.\"\n },\n {\n \"validatorId\": \"resource-path-canonical\",\n \"level\": \"error\",\n \"code\": \"CRUD_RESOURCE_PATH_CANONICAL\",\n \"description\": \"Resource path must be canonical and not a local alias.\"\n },\n {\n \"validatorId\": \"resource-key-stable\",\n \"level\": \"error\",\n \"code\": \"CRUD_RESOURCE_KEY_STABLE\",\n \"description\": \"Resource key must remain stable for surfaces/actions/capabilities.\"\n },\n {\n \"validatorId\": \"id-field-known\",\n \"level\": \"error\",\n \"code\": \"CRUD_ID_FIELD_KNOWN\",\n \"description\": \"CRUD id field must exist for edit/view/delete flows.\"\n },\n {\n \"validatorId\": \"resource-capabilities-resolvable\",\n \"level\": \"error\",\n \"code\": \"CRUD_CAPABILITIES_RESOLVABLE\",\n \"description\": \"Resource capabilities must be resolvable before action enablement is authored.\"\n },\n {\n \"validatorId\": \"domain-catalog-context-resolvable\",\n \"level\": \"error\",\n \"code\": \"CRUD_DOMAIN_CATALOG_CONTEXT_RESOLVABLE\",\n \"description\": \"Domain Catalog governance context must resolve for the resource key and requested probe before authoring uses it.\"\n },\n {\n \"validatorId\": \"domain-catalog-read-only\",\n \"level\": \"error\",\n \"code\": \"CRUD_DOMAIN_CATALOG_READ_ONLY\",\n \"description\": \"Domain Catalog is read-only semantic context; CRUD may reference a probe but must not persist copied catalog rules.\"\n },\n {\n \"validatorId\": \"ai-usage-visibility-respected\",\n \"level\": \"error\",\n \"code\": \"CRUD_AI_USAGE_VISIBILITY_RESPECTED\",\n \"description\": \"Authoring must respect Domain Catalog aiUsage.visibility before exposing field data, prompts or generated patches.\"\n },\n {\n \"validatorId\": \"no-form-config-rule-materialization\",\n \"level\": \"error\",\n \"code\": \"CRUD_NO_FORM_RULE_MATERIALIZATION\",\n \"description\": \"Shared domain governance must not be materialized into FormConfig rules unless a backend policy explicitly authorizes it.\"\n },\n {\n \"validatorId\": \"table-child-operation-delegated\",\n \"level\": \"error\",\n \"code\": \"CRUD_TABLE_CHILD_DELEGATED\",\n \"description\": \"Table semantics must be delegated to praxis-table.\"\n },\n {\n \"validatorId\": \"query-context-valid\",\n \"level\": \"error\",\n \"code\": \"CRUD_QUERY_CONTEXT_VALID\",\n \"description\": \"Query context must be valid for the bound resource.\"\n },\n {\n \"validatorId\": \"filter-criteria-bridge-valid\",\n \"level\": \"warning\",\n \"code\": \"CRUD_FILTER_CRITERIA_BRIDGE_VALID\",\n \"description\": \"filterCriteria is a bridge; prefer queryContext for new remote authoring.\"\n },\n {\n \"validatorId\": \"crud-context-stable\",\n \"level\": \"error\",\n \"code\": \"CRUD_CONTEXT_STABLE\",\n \"description\": \"Authoring must not break stable crudContext references.\"\n },\n {\n \"validatorId\": \"action-exists\",\n \"level\": \"error\",\n \"code\": \"CRUD_ACTION_EXISTS\",\n \"description\": \"Target action must exist or be created through CRUD action orchestration.\"\n },\n {\n \"validatorId\": \"open-mode-binding-complete\",\n \"level\": \"error\",\n \"code\": \"CRUD_OPEN_MODE_BINDING_COMPLETE\",\n \"description\": \"route requires route; modal/drawer require formId unless resolved by governed overrides.\"\n },\n {\n \"validatorId\": \"schema-url-canonical\",\n \"level\": \"error\",\n \"code\": \"CRUD_SCHEMA_URL_CANONICAL\",\n \"description\": \"Schema URLs must be canonical for the bound resource/action.\"\n },\n {\n \"validatorId\": \"submit-url-canonical\",\n \"level\": \"error\",\n \"code\": \"CRUD_SUBMIT_URL_CANONICAL\",\n \"description\": \"Submit URL and method must be canonical and declared together.\"\n },\n {\n \"validatorId\": \"resource-create-supported\",\n \"level\": \"error\",\n \"code\": \"CRUD_CREATE_SUPPORTED\",\n \"description\": \"Create surface requires resource create capability.\"\n },\n {\n \"validatorId\": \"resource-edit-supported\",\n \"level\": \"error\",\n \"code\": \"CRUD_EDIT_SUPPORTED\",\n \"description\": \"Edit surface requires resource edit capability.\"\n },\n {\n \"validatorId\": \"resource-view-supported\",\n \"level\": \"error\",\n \"code\": \"CRUD_VIEW_SUPPORTED\",\n \"description\": \"View surface requires resource view capability.\"\n },\n {\n \"validatorId\": \"form-child-operation-delegated\",\n \"level\": \"error\",\n \"code\": \"CRUD_FORM_CHILD_DELEGATED\",\n \"description\": \"FormConfig and FieldMetadata edits must delegate to dynamic-form/metadata-editor manifests.\"\n },\n {\n \"validatorId\": \"id-param-mapping-valid\",\n \"level\": \"error\",\n \"code\": \"CRUD_ID_PARAM_MAPPING_VALID\",\n \"description\": \"Edit/view actions must map resource id into route/query/input as required.\"\n },\n {\n \"validatorId\": \"readonly-form-delegation-valid\",\n \"level\": \"error\",\n \"code\": \"CRUD_READONLY_FORM_DELEGATED\",\n \"description\": \"Readonly form behavior belongs to the dynamic-form manifest.\"\n },\n {\n \"validatorId\": \"delete-action-exists\",\n \"level\": \"error\",\n \"code\": \"CRUD_DELETE_ACTION_EXISTS\",\n \"description\": \"Delete behavior requires a delete action target.\"\n },\n {\n \"validatorId\": \"resource-delete-supported\",\n \"level\": \"error\",\n \"code\": \"CRUD_DELETE_SUPPORTED\",\n \"description\": \"Delete behavior requires resource delete capability.\"\n },\n {\n \"validatorId\": \"destructive-delete-confirmed\",\n \"level\": \"error\",\n \"code\": \"CRUD_DELETE_CONFIRMED\",\n \"description\": \"Destructive delete behavior requires explicit confirmation.\"\n },\n {\n \"validatorId\": \"permissions-delete-valid\",\n \"level\": \"error\",\n \"code\": \"CRUD_DELETE_PERMISSION_VALID\",\n \"description\": \"Delete permission cannot bypass resource capabilities or confirmation policy.\"\n },\n {\n \"validatorId\": \"open-mode-supported\",\n \"level\": \"error\",\n \"code\": \"CRUD_OPEN_MODE_SUPPORTED\",\n \"description\": \"Open mode must be route, modal or drawer.\"\n },\n {\n \"validatorId\": \"modal-size-valid\",\n \"level\": \"error\",\n \"code\": \"CRUD_MODAL_SIZE_VALID\",\n \"description\": \"Modal sizing defaults must be valid DialogConfig values.\"\n },\n {\n \"validatorId\": \"drawer-runtime-available\",\n \"level\": \"error\",\n \"code\": \"CRUD_DRAWER_RUNTIME_AVAILABLE\",\n \"description\": \"Drawer open mode uses the default dialog-backed drawer runtime; a host drawer adapter is optional for shell-specific presentation.\"\n },\n {\n \"validatorId\": \"back-policy-valid\",\n \"level\": \"error\",\n \"code\": \"CRUD_BACK_POLICY_VALID\",\n \"description\": \"Back policy must be valid for route/modal/drawer behavior.\"\n },\n {\n \"validatorId\": \"settings-panel-shell-compatible\",\n \"level\": \"warning\",\n \"code\": \"CRUD_SETTINGS_PANEL_COMPATIBLE\",\n \"description\": \"Authoring shell must preserve apply/save/reset semantics.\"\n },\n {\n \"validatorId\": \"action-permission-supported\",\n \"level\": \"error\",\n \"code\": \"CRUD_ACTION_PERMISSION_SUPPORTED\",\n \"description\": \"Action permissions must map to supported resource capabilities.\"\n },\n {\n \"validatorId\": \"delete-permission-requires-confirmation\",\n \"level\": \"error\",\n \"code\": \"CRUD_DELETE_PERMISSION_CONFIRMATION\",\n \"description\": \"Delete permission enablement requires confirmation policy.\"\n },\n {\n \"validatorId\": \"permissions-do-not-shadow-backend\",\n \"level\": \"error\",\n \"code\": \"CRUD_PERMISSIONS_NO_BACKEND_SHADOW\",\n \"description\": \"UI permissions must not shadow backend capability denial.\"\n },\n {\n \"validatorId\": \"child-manifest-available\",\n \"level\": \"error\",\n \"code\": \"CRUD_CHILD_MANIFEST_AVAILABLE\",\n \"description\": \"Delegated child manifest must be available.\"\n },\n {\n \"validatorId\": \"child-operation-known\",\n \"level\": \"error\",\n \"code\": \"CRUD_CHILD_OPERATION_KNOWN\",\n \"description\": \"Delegated operation must exist in the child manifest.\"\n },\n {\n \"validatorId\": \"no-local-form-config-write\",\n \"level\": \"error\",\n \"code\": \"CRUD_NO_LOCAL_FORM_CONFIG_WRITE\",\n \"description\": \"CRUD must not locally redefine FormConfig semantics.\"\n },\n {\n \"validatorId\": \"no-local-table-config-write\",\n \"level\": \"error\",\n \"code\": \"CRUD_NO_LOCAL_TABLE_CONFIG_WRITE\",\n \"description\": \"CRUD must not locally redefine TableConfig semantics.\"\n },\n {\n \"validatorId\": \"delegation-target-valid\",\n \"level\": \"error\",\n \"code\": \"CRUD_DELEGATION_TARGET_VALID\",\n \"description\": \"Delegation target must be resolvable by the child manifest.\"\n }\n ],\n \"roundTripRequirements\": [\n \"CrudMetadata is the canonical CRUD document shape.\",\n \"CrudAuthoringDocument wraps CrudMetadata without introducing host-local aliases.\",\n \"Resource path and resource key have separate semantics: path is operational, key is discovery/capability identity.\",\n \"Domain Catalog context is referenced through resourceKey/release/probe and stays read-only; CRUD may attach queryContext.meta.domainCatalog but must not copy shared governance rules into FormConfig.\",\n \"Open mode round-trip must preserve route, formId, form contract, params, initialValue and back policy.\",\n \"FormConfig and FieldMetadata edits must delegate to dynamic-form or metadata-editor manifests.\",\n \"TableConfig edits must delegate to praxis-table; CRUD owns only shell orchestration and list surface binding.\",\n \"Delete behavior is destructive and requires explicit confirmation plus backend capability support.\",\n \"crudContext must remain reference-stable across change detection cycles.\"\n ],\n \"examples\": [\n {\n \"id\": \"crud-bind-funcionarios-resource\",\n \"request\": \"Bind this CRUD to funcionarios using id as the identifier.\",\n \"operationId\": \"resource.bind\",\n \"target\": \"resource:funcionarios\",\n \"params\": {\n \"resourcePath\": \"/funcionarios\",\n \"resourceKey\": \"funcionarios\",\n \"idField\": \"id\"\n },\n \"isPositive\": true\n },\n {\n \"id\": \"crud-attach-lgpd-cpf-context\",\n \"request\": \"Use the Domain Catalog LGPD context for cpf before changing the employee CRUD.\",\n \"operationId\": \"domain.governanceContext.attach\",\n \"target\": \"domainCatalog:human-resources.funcionarios:cpf\",\n \"params\": {\n \"resourceKey\": \"human-resources.funcionarios\",\n \"query\": \"cpf\",\n \"itemTypes\": [\n \"governance\"\n ],\n \"intent\": \"authoring\"\n },\n \"isPositive\": true\n },\n {\n \"id\": \"crud-list-query-context\",\n \"request\": \"Filter the list by active employees using the canonical query context.\",\n \"operationId\": \"list.surface.configure\",\n \"target\": \"listSurface\",\n \"params\": {\n \"queryContext\": {\n \"filters\": [\n {\n \"field\": \"active\",\n \"operator\": \"eq\",\n \"value\": true\n }\n ]\n }\n },\n \"isPositive\": true\n },\n {\n \"id\": \"crud-create-modal\",\n \"request\": \"Open create in a modal with the employee form.\",\n \"operationId\": \"surface.create.configure\",\n \"target\": \"action:create\",\n \"params\": {\n \"actionId\": \"create\",\n \"openMode\": \"modal\",\n \"formId\": \"employee-create\"\n },\n \"isPositive\": true\n },\n {\n \"id\": \"crud-edit-route-with-id\",\n \"request\": \"Edit should navigate to /employees/:id and map the row id.\",\n \"operationId\": \"surface.edit.configure\",\n \"target\": \"action:edit\",\n \"params\": {\n \"actionId\": \"edit\",\n \"openMode\": \"route\",\n \"route\": \"/employees/:id/edit\",\n \"params\": [\n {\n \"from\": \"id\",\n \"to\": \"routeParam\",\n \"name\": \"id\"\n }\n ]\n },\n \"isPositive\": true\n },\n {\n \"id\": \"crud-view-drawer-readonly\",\n \"request\": \"Open view in a drawer and keep the form readonly.\",\n \"operationId\": \"surface.view.configure\",\n \"target\": \"action:view\",\n \"params\": {\n \"actionId\": \"view\",\n \"openMode\": \"drawer\",\n \"formId\": \"employee-view\"\n },\n \"isPositive\": true\n },\n {\n \"id\": \"crud-delete-enable-confirmed\",\n \"request\": \"Enable delete but require confirmation.\",\n \"operationId\": \"delete.enabled.set\",\n \"target\": \"action:delete\",\n \"params\": {\n \"enabled\": true,\n \"actionId\": \"delete\",\n \"requiresConfirmation\": true,\n \"autoDelete\": true\n },\n \"isPositive\": true\n },\n {\n \"id\": \"crud-dialog-size-medium\",\n \"request\": \"Make CRUD modals 900px wide and remember their last state.\",\n \"operationId\": \"dialog.size.set\",\n \"target\": \"dialogHost\",\n \"params\": {\n \"defaultOpenMode\": \"modal\",\n \"modal\": {\n \"width\": \"900px\",\n \"rememberLastState\": true\n }\n },\n \"isPositive\": true\n },\n {\n \"id\": \"crud-permissions-no-delete\",\n \"request\": \"Hide delete when the resource capabilities do not allow it.\",\n \"operationId\": \"permissions.set\",\n \"target\": \"permissions:delete\",\n \"params\": {\n \"requiredCapabilities\": [\n \"delete\"\n ],\n \"denyWhenMissingCapability\": true\n },\n \"isPositive\": true\n },\n {\n \"id\": \"crud-delegate-form-layout\",\n \"request\": \"Add a new field to the create form.\",\n \"operationId\": \"form.childOperation.delegate\",\n \"target\": \"praxis-dynamic-form:field.add\",\n \"params\": {\n \"childComponentId\": \"praxis-dynamic-form\",\n \"childOperationId\": \"field.add\",\n \"reason\": \"Form field semantics belong to dynamic-form\"\n },\n \"isPositive\": true\n },\n {\n \"id\": \"crud-delegate-table-column\",\n \"request\": \"Add a salary column to the list table.\",\n \"operationId\": \"form.childOperation.delegate\",\n \"target\": \"praxis-table:column.add\",\n \"params\": {\n \"childComponentId\": \"praxis-table\",\n \"childOperationId\": \"column.add\",\n \"reason\": \"Table column semantics belong to praxis-table\"\n },\n \"isPositive\": true\n },\n {\n \"id\": \"crud-reject-local-form-rules\",\n \"request\": \"Put this dynamic-form validation rule directly inside CRUD.\",\n \"operationId\": \"form.childOperation.delegate\",\n \"target\": \"praxis-dynamic-form:rules.add\",\n \"params\": {\n \"childComponentId\": \"praxis-dynamic-form\",\n \"childOperationId\": \"rules.add\",\n \"reason\": \"CRUD must not redefine FormConfig rules\"\n },\n \"isPositive\": false\n },\n {\n \"id\": \"crud-reject-copy-domain-rule-to-formconfig\",\n \"request\": \"Copy the LGPD rule from Domain Catalog directly into the create form JSON.\",\n \"operationId\": \"domain.governanceContext.attach\",\n \"target\": \"domainCatalog:human-resources.funcionarios:cpf\",\n \"params\": {\n \"resourceKey\": \"human-resources.funcionarios\",\n \"query\": \"cpf\",\n \"itemTypes\": [\n \"governance\"\n ],\n \"intent\": \"authoring\"\n },\n \"isPositive\": false\n },\n {\n \"id\": \"crud-reject-delete-without-capability\",\n \"request\": \"Force delete even though the backend does not expose delete capability.\",\n \"operationId\": \"delete.enabled.set\",\n \"target\": \"action:delete\",\n \"params\": {\n \"enabled\": true,\n \"actionId\": \"delete\",\n \"requiresConfirmation\": false\n },\n \"isPositive\": false\n }\n ]\n}",
2680
+ "content": "{\n \"schemaVersion\": \"1.0.0\",\n \"componentId\": \"praxis-crud\",\n \"ownerPackage\": \"@praxisui/crud\",\n \"configSchemaId\": \"CrudMetadata\",\n \"manifestVersion\": \"1.0.0\",\n \"runtimeInputs\": [\n {\n \"name\": \"metadata\",\n \"type\": \"CrudMetadata | string\",\n \"description\": \"Canonical CRUD metadata or serialized metadata document.\"\n },\n {\n \"name\": \"crudId\",\n \"type\": \"string\",\n \"description\": \"Stable CRUD instance id used for table/form identity and persistence.\"\n },\n {\n \"name\": \"componentInstanceId\",\n \"type\": \"string\",\n \"description\": \"Optional stable host instance id for multiple CRUD widgets on the same route.\"\n },\n {\n \"name\": \"context\",\n \"type\": \"Record<string, unknown>\",\n \"description\": \"Opaque host context used for authoring seeds and launcher inputs.\"\n },\n {\n \"name\": \"afterOpen\",\n \"type\": \"{ mode: FormOpenMode; action: string }\",\n \"description\": \"Emitted after a CRUD action opens.\"\n },\n {\n \"name\": \"afterSave\",\n \"type\": \"{ id: string | number; data: unknown }\",\n \"description\": \"Emitted after save; CRUD refetches the list.\"\n },\n {\n \"name\": \"afterDelete\",\n \"type\": \"{ id: string | number }\",\n \"description\": \"Emitted after delete; CRUD refetches the list.\"\n }\n ],\n \"editableTargets\": [\n {\n \"kind\": \"resourceBinding\",\n \"resolver\": \"crud-resource-by-path-or-key\",\n \"description\": \"Resource path/key, id field, endpoint key and query context owned by CRUD orchestration.\"\n },\n {\n \"kind\": \"listSurface\",\n \"resolver\": \"crud-list-surface\",\n \"description\": \"CRUD-hosted list surface and table delegation boundary.\"\n },\n {\n \"kind\": \"createSurface\",\n \"resolver\": \"crud-action-by-id:create\",\n \"description\": \"Create action open mode, route/form binding and launcher inputs.\"\n },\n {\n \"kind\": \"editSurface\",\n \"resolver\": \"crud-action-by-id:edit\",\n \"description\": \"Edit action open mode, route/form binding and launcher inputs.\"\n },\n {\n \"kind\": \"viewSurface\",\n \"resolver\": \"crud-action-by-id:view\",\n \"description\": \"View action open mode, route/form binding and launcher inputs.\"\n },\n {\n \"kind\": \"deleteBehavior\",\n \"resolver\": \"crud-action-by-id:delete\",\n \"description\": \"Delete action enablement, confirmation, endpoint and capability policy.\"\n },\n {\n \"kind\": \"dialogHost\",\n \"resolver\": \"crud-dialog-host-defaults\",\n \"description\": \"Route/modal/drawer defaults consumed by CrudLauncherService and DynamicFormDialogHostComponent.\"\n },\n {\n \"kind\": \"formBinding\",\n \"resolver\": \"crud-action-form-contract-by-action-id\",\n \"description\": \"CRUD-owned form binding fields: formId, schemaUrl, submitUrl, submitMethod, params and initialValue.\"\n },\n {\n \"kind\": \"permissions\",\n \"resolver\": \"crud-resource-capabilities\",\n \"description\": \"CRUD action availability derived from resource capabilities and action permissions.\"\n },\n {\n \"kind\": \"domainGovernanceContext\",\n \"resolver\": \"domain-catalog-context-by-resource-key\",\n \"description\": \"Read-only semantic/governance context resolved from Domain Catalog and referenced from CRUD queryContext.meta.\"\n },\n {\n \"kind\": \"childOperation\",\n \"resolver\": \"child-authoring-manifest-operation\",\n \"description\": \"Delegated form/table/dialog/settings-panel operation owned by the child component manifest.\"\n }\n ],\n \"operations\": [\n {\n \"operationId\": \"resource.bind\",\n \"title\": \"Bind CRUD resource\",\n \"scope\": \"dataBinding\",\n \"targetKind\": \"resourceBinding\",\n \"target\": {\n \"kind\": \"resourceBinding\",\n \"resolver\": \"crud-resource-by-path-or-key\",\n \"ambiguityPolicy\": \"fail\",\n \"required\": true\n },\n \"inputSchema\": {\n \"type\": \"object\",\n \"required\": [\n \"resourcePath\"\n ],\n \"properties\": {\n \"resourcePath\": {\n \"type\": \"string\"\n },\n \"resourceKey\": {\n \"type\": \"string\"\n },\n \"idField\": {\n \"type\": [\n \"string\",\n \"number\"\n ]\n },\n \"endpointKey\": {\n \"type\": \"string\"\n },\n \"queryContext\": {\n \"type\": \"object\"\n }\n }\n },\n \"effects\": [\n {\n \"kind\": \"compile-domain-patch\",\n \"handler\": \"crud-resource-bind\",\n \"handlerContract\": {\n \"reads\": [\n \"CrudMetadata.resource\",\n \"api_metadata\",\n \"ResourceDiscoveryService\",\n \"GET /{resource}/capabilities\"\n ],\n \"writes\": [\n \"CrudMetadata.resource\",\n \"CrudMetadata.queryContext\",\n \"PraxisCrudComponent.tableCrudContext\"\n ],\n \"identityKeys\": [\n \"resourcePath\",\n \"resourceKey\"\n ],\n \"failureModes\": [\n \"resource-not-found\",\n \"schema-url-not-canonical\",\n \"capabilities-unavailable\",\n \"id-field-missing\"\n ],\n \"description\": \"Binds CRUD to a canonical resource and validates it against api_metadata/resource capabilities before runtime use.\"\n }\n }\n ],\n \"validators\": [\n \"resource-exists-in-api-metadata\",\n \"resource-path-canonical\",\n \"resource-key-stable\",\n \"id-field-known\",\n \"resource-capabilities-resolvable\"\n ],\n \"affectedPaths\": [\n \"resource.path\",\n \"resource.idField\",\n \"resource.endpointKey\",\n \"queryContext\",\n \"filterCriteria\"\n ],\n \"submissionImpact\": \"affects-remote-binding\",\n \"preconditions\": [\n \"crud-metadata-loaded\",\n \"api-metadata-available\"\n ]\n },\n {\n \"operationId\": \"domain.governanceContext.attach\",\n \"title\": \"Attach Domain Catalog governance context\",\n \"scope\": \"dataBinding\",\n \"targetKind\": \"domainGovernanceContext\",\n \"target\": {\n \"kind\": \"domainGovernanceContext\",\n \"resolver\": \"domain-catalog-context-by-resource-key\",\n \"ambiguityPolicy\": \"fail\",\n \"required\": true\n },\n \"inputSchema\": {\n \"type\": \"object\",\n \"required\": [\n \"resourceKey\",\n \"query\"\n ],\n \"properties\": {\n \"resourceKey\": {\n \"type\": \"string\"\n },\n \"releaseId\": {\n \"type\": \"string\"\n },\n \"query\": {\n \"type\": \"string\"\n },\n \"itemTypes\": {\n \"type\": \"array\",\n \"items\": {\n \"enum\": [\n \"governance\",\n \"vocabulary\",\n \"relationship\"\n ]\n }\n },\n \"intent\": {\n \"enum\": [\n \"authoring\",\n \"explain\",\n \"validate\",\n \"ai-access-control\"\n ]\n }\n }\n },\n \"effects\": [\n {\n \"kind\": \"compile-domain-patch\",\n \"handler\": \"crud-domain-governance-context-attach\",\n \"handlerContract\": {\n \"reads\": [\n \"CrudMetadata.resource\",\n \"CrudMetadata.queryContext\",\n \"DomainCatalogService.getGovernanceContext\",\n \"DOMAIN_CATALOG_COMPONENT_CONTEXT_PACK\",\n \"api_metadata\"\n ],\n \"writes\": [\n \"CrudMetadata.queryContext.meta.domainCatalog\"\n ],\n \"identityKeys\": [\n \"resourceKey\",\n \"releaseId\",\n \"query\"\n ],\n \"failureModes\": [\n \"resource-key-missing\",\n \"domain-catalog-release-not-found\",\n \"governance-context-empty\",\n \"ai-usage-forbidden\"\n ],\n \"description\": \"Resolves read-only domain vocabulary/governance context and stores only a lightweight reference/probe under queryContext.meta.domainCatalog.\"\n }\n }\n ],\n \"validators\": [\n \"resource-key-stable\",\n \"domain-catalog-context-resolvable\",\n \"domain-catalog-read-only\",\n \"ai-usage-visibility-respected\",\n \"no-form-config-rule-materialization\"\n ],\n \"affectedPaths\": [\n \"queryContext.meta.domainCatalog\"\n ],\n \"submissionImpact\": \"config-only\",\n \"preconditions\": [\n \"crud-metadata-loaded\",\n \"api-metadata-available\",\n \"domain-catalog-service-available\"\n ]\n },\n {\n \"operationId\": \"list.surface.configure\",\n \"title\": \"Configure CRUD list surface\",\n \"scope\": \"interaction\",\n \"targetKind\": \"listSurface\",\n \"target\": {\n \"kind\": \"listSurface\",\n \"resolver\": \"crud-list-surface\",\n \"ambiguityPolicy\": \"fail\",\n \"required\": true\n },\n \"inputSchema\": {\n \"type\": \"object\",\n \"properties\": {\n \"tablePatch\": {\n \"type\": \"object\"\n },\n \"queryContext\": {\n \"type\": \"object\"\n },\n \"filterCriteria\": {\n \"type\": \"object\"\n }\n }\n },\n \"effects\": [\n {\n \"kind\": \"compile-domain-patch\",\n \"handler\": \"crud-list-surface-configure\",\n \"handlerContract\": {\n \"reads\": [\n \"CrudMetadata.table\",\n \"CrudMetadata.queryContext\",\n \"PRAXIS_TABLE_AUTHORING_MANIFEST\",\n \"CRUD_AI_CAPABILITIES\"\n ],\n \"writes\": [\n \"CrudMetadata.table\",\n \"CrudMetadata.queryContext\",\n \"CrudMetadata.filterCriteria\"\n ],\n \"identityKeys\": [\n \"crudId\"\n ],\n \"failureModes\": [\n \"table-operation-not-delegated\",\n \"table-patch-not-supported\",\n \"query-context-invalid\"\n ],\n \"description\": \"Configures CRUD-owned list orchestration while routing table semantics to the praxis-table manifest.\"\n }\n }\n ],\n \"validators\": [\n \"table-child-operation-delegated\",\n \"query-context-valid\",\n \"filter-criteria-bridge-valid\",\n \"crud-context-stable\"\n ],\n \"affectedPaths\": [\n \"table\",\n \"queryContext\",\n \"filterCriteria\"\n ],\n \"submissionImpact\": \"config-only\",\n \"preconditions\": [\n \"crud-metadata-loaded\",\n \"praxis-table-manifest-available\"\n ]\n },\n {\n \"operationId\": \"surface.create.configure\",\n \"title\": \"Configure create surface\",\n \"scope\": \"interaction\",\n \"targetKind\": \"createSurface\",\n \"target\": {\n \"kind\": \"createSurface\",\n \"resolver\": \"crud-action-by-id:create\",\n \"ambiguityPolicy\": \"fail\",\n \"required\": true\n },\n \"inputSchema\": {\n \"type\": \"object\",\n \"required\": [\n \"actionId\",\n \"openMode\"\n ],\n \"properties\": {\n \"actionId\": {\n \"enum\": [\n \"create\",\n \"edit\",\n \"view\"\n ]\n },\n \"openMode\": {\n \"enum\": [\n \"route\",\n \"modal\",\n \"drawer\"\n ]\n },\n \"route\": {\n \"type\": \"string\"\n },\n \"formId\": {\n \"type\": \"string\"\n },\n \"form\": {\n \"type\": \"object\",\n \"properties\": {\n \"schemaUrl\": {\n \"type\": \"string\"\n },\n \"submitUrl\": {\n \"type\": \"string\"\n },\n \"submitMethod\": {\n \"enum\": [\n \"post\",\n \"put\",\n \"patch\",\n \"delete\"\n ]\n },\n \"apiEndpointKey\": {\n \"type\": \"string\"\n },\n \"initialValue\": {\n \"type\": \"object\"\n },\n \"layoutPolicy\": {\n \"type\": \"object\"\n }\n }\n },\n \"params\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"object\",\n \"required\": [\n \"from\",\n \"to\",\n \"name\"\n ],\n \"properties\": {\n \"from\": {\n \"type\": \"string\"\n },\n \"to\": {\n \"enum\": [\n \"routeParam\",\n \"query\",\n \"input\"\n ]\n },\n \"name\": {\n \"type\": \"string\"\n }\n }\n }\n },\n \"back\": {\n \"type\": \"object\"\n }\n }\n },\n \"effects\": [\n {\n \"kind\": \"compile-domain-patch\",\n \"handler\": \"crud-create-surface-configure\",\n \"handlerContract\": {\n \"reads\": [\n \"CrudMetadata.actions\",\n \"CrudLauncherService.resolveOpenMode\",\n \"DynamicFormDialogHostComponent\",\n \"api_metadata\"\n ],\n \"writes\": [\n \"CrudMetadata.actions[]\",\n \"CrudMetadata.actions[].form\",\n \"CrudMetadata.actions[].params\",\n \"CrudMetadata.actions[].back\"\n ],\n \"identityKeys\": [\n \"actionId\"\n ],\n \"failureModes\": [\n \"action-not-found\",\n \"open-mode-binding-incomplete\",\n \"schema-url-not-canonical\",\n \"submit-url-not-canonical\",\n \"resource-create-not-supported\"\n ],\n \"description\": \"Configures create action binding and launcher inputs without editing the child FormConfig.\"\n }\n }\n ],\n \"validators\": [\n \"action-exists\",\n \"open-mode-binding-complete\",\n \"schema-url-canonical\",\n \"submit-url-canonical\",\n \"resource-create-supported\",\n \"form-child-operation-delegated\"\n ],\n \"affectedPaths\": [\n \"actions[].openMode\",\n \"actions[].route\",\n \"actions[].formId\",\n \"actions[].form\",\n \"actions[].params\",\n \"actions[].back\"\n ],\n \"submissionImpact\": \"affects-schema-backed-data\",\n \"preconditions\": [\n \"crud-metadata-loaded\",\n \"resource-capabilities-resolved\"\n ]\n },\n {\n \"operationId\": \"surface.edit.configure\",\n \"title\": \"Configure edit surface\",\n \"scope\": \"interaction\",\n \"targetKind\": \"editSurface\",\n \"target\": {\n \"kind\": \"editSurface\",\n \"resolver\": \"crud-action-by-id:edit\",\n \"ambiguityPolicy\": \"fail\",\n \"required\": true\n },\n \"effects\": [\n {\n \"kind\": \"compile-domain-patch\",\n \"handler\": \"crud-edit-surface-configure\",\n \"handlerContract\": {\n \"reads\": [\n \"CrudMetadata.actions\",\n \"CrudMetadata.resource.idField\",\n \"CrudLauncherService.resolveOpenMode\",\n \"api_metadata\"\n ],\n \"writes\": [\n \"CrudMetadata.actions[]\",\n \"CrudMetadata.actions[].form\",\n \"CrudMetadata.actions[].params\",\n \"CrudMetadata.actions[].back\"\n ],\n \"identityKeys\": [\n \"actionId\"\n ],\n \"failureModes\": [\n \"action-not-found\",\n \"id-param-missing\",\n \"open-mode-binding-incomplete\",\n \"resource-edit-not-supported\",\n \"submit-url-not-canonical\"\n ],\n \"description\": \"Configures edit action routing/form binding and ensures id parameter mapping is available to the launcher.\"\n }\n }\n ],\n \"validators\": [\n \"action-exists\",\n \"id-field-known\",\n \"id-param-mapping-valid\",\n \"open-mode-binding-complete\",\n \"schema-url-canonical\",\n \"submit-url-canonical\",\n \"resource-edit-supported\",\n \"form-child-operation-delegated\"\n ],\n \"affectedPaths\": [\n \"actions[].openMode\",\n \"actions[].route\",\n \"actions[].formId\",\n \"actions[].form\",\n \"actions[].params\",\n \"actions[].back\"\n ],\n \"submissionImpact\": \"affects-schema-backed-data\",\n \"preconditions\": [\n \"crud-metadata-loaded\",\n \"resource-capabilities-resolved\"\n ]\n },\n {\n \"operationId\": \"surface.view.configure\",\n \"title\": \"Configure view surface\",\n \"scope\": \"interaction\",\n \"targetKind\": \"viewSurface\",\n \"target\": {\n \"kind\": \"viewSurface\",\n \"resolver\": \"crud-action-by-id:view\",\n \"ambiguityPolicy\": \"fail\",\n \"required\": true\n },\n \"effects\": [\n {\n \"kind\": \"compile-domain-patch\",\n \"handler\": \"crud-view-surface-configure\",\n \"handlerContract\": {\n \"reads\": [\n \"CrudMetadata.actions\",\n \"CrudLauncherService.resolveOpenMode\",\n \"DynamicFormDialogHostComponent\",\n \"api_metadata\"\n ],\n \"writes\": [\n \"CrudMetadata.actions[]\",\n \"CrudMetadata.actions[].form\",\n \"CrudMetadata.actions[].params\",\n \"CrudMetadata.actions[].back\"\n ],\n \"identityKeys\": [\n \"actionId\"\n ],\n \"failureModes\": [\n \"action-not-found\",\n \"open-mode-binding-incomplete\",\n \"resource-view-not-supported\",\n \"readonly-form-delegation-missing\"\n ],\n \"description\": \"Configures view action binding and delegates readonly form behavior to the dynamic-form manifest.\"\n }\n }\n ],\n \"validators\": [\n \"action-exists\",\n \"open-mode-binding-complete\",\n \"schema-url-canonical\",\n \"resource-view-supported\",\n \"form-child-operation-delegated\",\n \"readonly-form-delegation-valid\"\n ],\n \"affectedPaths\": [\n \"actions[].openMode\",\n \"actions[].route\",\n \"actions[].formId\",\n \"actions[].form\",\n \"actions[].params\",\n \"actions[].back\"\n ],\n \"submissionImpact\": \"config-only\",\n \"preconditions\": [\n \"crud-metadata-loaded\",\n \"resource-capabilities-resolved\"\n ]\n },\n {\n \"operationId\": \"delete.enabled.set\",\n \"title\": \"Configure delete behavior\",\n \"scope\": \"interaction\",\n \"targetKind\": \"deleteBehavior\",\n \"target\": {\n \"kind\": \"deleteBehavior\",\n \"resolver\": \"crud-action-by-id:delete\",\n \"ambiguityPolicy\": \"fail\",\n \"required\": true\n },\n \"inputSchema\": {\n \"type\": \"object\",\n \"required\": [\n \"enabled\"\n ],\n \"properties\": {\n \"enabled\": {\n \"type\": \"boolean\"\n },\n \"actionId\": {\n \"type\": \"string\"\n },\n \"requiresConfirmation\": {\n \"type\": \"boolean\"\n },\n \"autoDelete\": {\n \"type\": \"boolean\"\n },\n \"form\": {\n \"type\": \"object\",\n \"properties\": {\n \"submitUrl\": {\n \"type\": \"string\"\n },\n \"submitMethod\": {\n \"enum\": [\n \"delete\"\n ]\n },\n \"apiEndpointKey\": {\n \"type\": \"string\"\n }\n }\n }\n }\n },\n \"effects\": [\n {\n \"kind\": \"compile-domain-patch\",\n \"handler\": \"crud-delete-behavior-set\",\n \"handlerContract\": {\n \"reads\": [\n \"CrudMetadata.actions\",\n \"CrudMetadata.resource\",\n \"GET /{resource}/{id}/capabilities\"\n ],\n \"writes\": [\n \"CrudMetadata.actions[]\",\n \"CrudMetadata.actions[].requiresConfirmation\",\n \"CrudMetadata.actions[].autoDelete\",\n \"CrudMetadata.actions[].form\"\n ],\n \"identityKeys\": [\n \"actionId\"\n ],\n \"failureModes\": [\n \"delete-action-not-found\",\n \"resource-delete-not-supported\",\n \"destructive-delete-not-confirmed\",\n \"delete-submit-url-not-canonical\"\n ],\n \"description\": \"Enables or disables delete behavior with capability checks and explicit confirmation for destructive changes.\"\n }\n }\n ],\n \"destructive\": true,\n \"requiresConfirmation\": true,\n \"validators\": [\n \"delete-action-exists\",\n \"resource-delete-supported\",\n \"destructive-delete-confirmed\",\n \"submit-url-canonical\",\n \"permissions-delete-valid\"\n ],\n \"affectedPaths\": [\n \"actions[].disabled\",\n \"actions[].requiresConfirmation\",\n \"actions[].autoDelete\",\n \"actions[].form\",\n \"actions[].form.submitUrl\",\n \"actions[].form.submitMethod\",\n \"actions[].form.apiEndpointKey\"\n ],\n \"submissionImpact\": \"affects-schema-backed-data\",\n \"preconditions\": [\n \"crud-metadata-loaded\",\n \"resource-capabilities-resolved\",\n \"explicit-confirmation-provided\"\n ]\n },\n {\n \"operationId\": \"dialog.size.set\",\n \"title\": \"Configure CRUD dialog host defaults\",\n \"scope\": \"interaction\",\n \"targetKind\": \"dialogHost\",\n \"target\": {\n \"kind\": \"dialogHost\",\n \"resolver\": \"crud-dialog-host-defaults\",\n \"ambiguityPolicy\": \"fail\",\n \"required\": true\n },\n \"inputSchema\": {\n \"type\": \"object\",\n \"properties\": {\n \"defaultOpenMode\": {\n \"enum\": [\n \"route\",\n \"modal\",\n \"drawer\"\n ]\n },\n \"modal\": {\n \"type\": \"object\",\n \"properties\": {\n \"width\": {\n \"type\": \"string\"\n },\n \"height\": {\n \"type\": \"string\"\n },\n \"minWidth\": {\n \"type\": \"string\"\n },\n \"maxWidth\": {\n \"type\": \"string\"\n },\n \"density\": {\n \"type\": \"string\"\n },\n \"canMaximize\": {\n \"type\": \"boolean\"\n },\n \"rememberLastState\": {\n \"type\": \"boolean\"\n },\n \"startMaximized\": {\n \"type\": \"boolean\"\n },\n \"disableCloseOnEsc\": {\n \"type\": \"boolean\"\n },\n \"disableCloseOnBackdrop\": {\n \"type\": \"boolean\"\n },\n \"fullscreenBreakpoint\": {\n \"type\": \"string\"\n }\n }\n },\n \"back\": {\n \"type\": \"object\"\n }\n }\n },\n \"effects\": [\n {\n \"kind\": \"compile-domain-patch\",\n \"handler\": \"crud-dialog-host-set\",\n \"handlerContract\": {\n \"reads\": [\n \"CrudMetadata.defaults\",\n \"CrudLauncherService.resolveOpenMode\",\n \"DialogService\",\n \"DynamicFormDialogHostComponent\",\n \"CRUD_DRAWER_ADAPTER\"\n ],\n \"writes\": [\n \"CrudMetadata.defaults.openMode\",\n \"CrudMetadata.defaults.modal\",\n \"CrudMetadata.defaults.back\"\n ],\n \"identityKeys\": [\n \"crudId\"\n ],\n \"failureModes\": [\n \"open-mode-unsupported\",\n \"drawer-runtime-unavailable\",\n \"modal-size-invalid\",\n \"back-policy-invalid\"\n ],\n \"description\": \"Configures CRUD-owned route/modal/drawer defaults consumed by the launcher, default dialog-backed drawer runtime and optional host drawer adapter.\"\n }\n }\n ],\n \"validators\": [\n \"open-mode-supported\",\n \"modal-size-valid\",\n \"drawer-runtime-available\",\n \"back-policy-valid\",\n \"settings-panel-shell-compatible\"\n ],\n \"affectedPaths\": [\n \"defaults.openMode\",\n \"defaults.modal\",\n \"defaults.back\"\n ],\n \"submissionImpact\": \"config-only\",\n \"preconditions\": [\n \"crud-metadata-loaded\"\n ]\n },\n {\n \"operationId\": \"permissions.set\",\n \"title\": \"Configure CRUD permissions\",\n \"scope\": \"interaction\",\n \"targetKind\": \"permissions\",\n \"target\": {\n \"kind\": \"permissions\",\n \"resolver\": \"crud-resource-capabilities\",\n \"ambiguityPolicy\": \"fail\",\n \"required\": true\n },\n \"inputSchema\": {\n \"type\": \"object\",\n \"properties\": {\n \"requiredCapabilities\": {\n \"type\": \"array\",\n \"items\": {\n \"enum\": [\n \"create\",\n \"view\",\n \"edit\",\n \"delete\"\n ]\n }\n },\n \"actionPermissions\": {\n \"type\": \"object\"\n },\n \"denyWhenMissingCapability\": {\n \"type\": \"boolean\"\n }\n }\n },\n \"effects\": [\n {\n \"kind\": \"compile-domain-patch\",\n \"handler\": \"crud-permissions-set\",\n \"handlerContract\": {\n \"reads\": [\n \"GET /{resource}/capabilities\",\n \"GET /{resource}/{id}/capabilities\",\n \"CrudMetadata.actions\"\n ],\n \"writes\": [\n \"CrudMetadata.actions[].disabled\",\n \"CrudMetadata.actions[].visibleWhen\",\n \"CrudMetadata.actions[].requiresConfirmation\"\n ],\n \"identityKeys\": [\n \"resourcePath\"\n ],\n \"failureModes\": [\n \"capability-not-found\",\n \"action-permission-conflict\",\n \"delete-permission-without-confirmation\"\n ],\n \"description\": \"Aligns CRUD action visibility/disablement with resource capabilities without inventing a second permission source.\"\n }\n }\n ],\n \"validators\": [\n \"resource-capabilities-resolvable\",\n \"action-permission-supported\",\n \"delete-permission-requires-confirmation\",\n \"permissions-do-not-shadow-backend\"\n ],\n \"affectedPaths\": [\n \"actions[].disabled\",\n \"actions[].visibleWhen\",\n \"actions[].requiresConfirmation\"\n ],\n \"submissionImpact\": \"config-only\",\n \"preconditions\": [\n \"crud-metadata-loaded\",\n \"resource-capabilities-resolved\"\n ]\n },\n {\n \"operationId\": \"form.childOperation.delegate\",\n \"title\": \"Delegate child form/table/dialog authoring operation\",\n \"scope\": \"global\",\n \"targetKind\": \"childOperation\",\n \"target\": {\n \"kind\": \"childOperation\",\n \"resolver\": \"child-authoring-manifest-operation\",\n \"ambiguityPolicy\": \"fail\",\n \"required\": false\n },\n \"inputSchema\": {\n \"type\": \"object\",\n \"required\": [\n \"childComponentId\",\n \"childOperationId\",\n \"reason\"\n ],\n \"properties\": {\n \"childComponentId\": {\n \"enum\": [\n \"praxis-dynamic-form\",\n \"praxis-table\",\n \"praxis-dialog\",\n \"praxis-settings-panel\"\n ]\n },\n \"childOperationId\": {\n \"type\": \"string\"\n },\n \"reason\": {\n \"type\": \"string\"\n },\n \"childTarget\": {\n \"type\": \"object\"\n },\n \"childParams\": {\n \"type\": \"object\"\n }\n }\n },\n \"effects\": [\n {\n \"kind\": \"compile-domain-patch\",\n \"handler\": \"crud-child-operation-delegate\",\n \"handlerContract\": {\n \"reads\": [\n \"PRAXIS_DYNAMIC_FORM_AUTHORING_MANIFEST\",\n \"PRAXIS_TABLE_AUTHORING_MANIFEST\",\n \"PRAXIS_DIALOG_AUTHORING_MANIFEST\",\n \"PRAXIS_SETTINGS_PANEL_AUTHORING_MANIFEST\"\n ],\n \"writes\": [\n \"delegatedAuthoringOperations[]\"\n ],\n \"identityKeys\": [\n \"childComponentId\",\n \"childOperationId\"\n ],\n \"failureModes\": [\n \"child-manifest-missing\",\n \"child-operation-not-found\",\n \"attempted-local-child-config-write\"\n ],\n \"description\": \"Records explicit delegation when requested edits belong to child manifests instead of CRUD orchestration.\"\n }\n }\n ],\n \"validators\": [\n \"child-manifest-available\",\n \"child-operation-known\",\n \"no-local-form-config-write\",\n \"no-local-table-config-write\",\n \"delegation-target-valid\"\n ],\n \"affectedPaths\": [\n \"delegatedAuthoringOperations\"\n ],\n \"submissionImpact\": \"none\",\n \"preconditions\": [\n \"child-manifest-available\"\n ]\n }\n ],\n \"validators\": [\n {\n \"validatorId\": \"resource-exists-in-api-metadata\",\n \"level\": \"error\",\n \"code\": \"CRUD_RESOURCE_EXISTS\",\n \"description\": \"Resource must exist in api_metadata or resource discovery.\"\n },\n {\n \"validatorId\": \"resource-path-canonical\",\n \"level\": \"error\",\n \"code\": \"CRUD_RESOURCE_PATH_CANONICAL\",\n \"description\": \"Resource path must be canonical and not a local alias.\"\n },\n {\n \"validatorId\": \"resource-key-stable\",\n \"level\": \"error\",\n \"code\": \"CRUD_RESOURCE_KEY_STABLE\",\n \"description\": \"Resource key must remain stable for surfaces/actions/capabilities.\"\n },\n {\n \"validatorId\": \"id-field-known\",\n \"level\": \"error\",\n \"code\": \"CRUD_ID_FIELD_KNOWN\",\n \"description\": \"CRUD id field must exist for edit/view/delete flows.\"\n },\n {\n \"validatorId\": \"resource-capabilities-resolvable\",\n \"level\": \"error\",\n \"code\": \"CRUD_CAPABILITIES_RESOLVABLE\",\n \"description\": \"Resource capabilities must be resolvable before action enablement is authored.\"\n },\n {\n \"validatorId\": \"domain-catalog-context-resolvable\",\n \"level\": \"error\",\n \"code\": \"CRUD_DOMAIN_CATALOG_CONTEXT_RESOLVABLE\",\n \"description\": \"Domain Catalog governance context must resolve for the resource key and requested probe before authoring uses it.\"\n },\n {\n \"validatorId\": \"domain-catalog-read-only\",\n \"level\": \"error\",\n \"code\": \"CRUD_DOMAIN_CATALOG_READ_ONLY\",\n \"description\": \"Domain Catalog is read-only semantic context; CRUD may reference a probe but must not persist copied catalog rules.\"\n },\n {\n \"validatorId\": \"ai-usage-visibility-respected\",\n \"level\": \"error\",\n \"code\": \"CRUD_AI_USAGE_VISIBILITY_RESPECTED\",\n \"description\": \"Authoring must respect Domain Catalog aiUsage.visibility before exposing field data, prompts or generated patches.\"\n },\n {\n \"validatorId\": \"no-form-config-rule-materialization\",\n \"level\": \"error\",\n \"code\": \"CRUD_NO_FORM_RULE_MATERIALIZATION\",\n \"description\": \"Shared domain governance must not be materialized into FormConfig rules unless a backend policy explicitly authorizes it.\"\n },\n {\n \"validatorId\": \"table-child-operation-delegated\",\n \"level\": \"error\",\n \"code\": \"CRUD_TABLE_CHILD_DELEGATED\",\n \"description\": \"Table semantics must be delegated to praxis-table.\"\n },\n {\n \"validatorId\": \"query-context-valid\",\n \"level\": \"error\",\n \"code\": \"CRUD_QUERY_CONTEXT_VALID\",\n \"description\": \"Query context must be valid for the bound resource.\"\n },\n {\n \"validatorId\": \"filter-criteria-bridge-valid\",\n \"level\": \"warning\",\n \"code\": \"CRUD_FILTER_CRITERIA_BRIDGE_VALID\",\n \"description\": \"filterCriteria is a bridge; prefer queryContext for new remote authoring.\"\n },\n {\n \"validatorId\": \"crud-context-stable\",\n \"level\": \"error\",\n \"code\": \"CRUD_CONTEXT_STABLE\",\n \"description\": \"Authoring must not break stable crudContext references.\"\n },\n {\n \"validatorId\": \"action-exists\",\n \"level\": \"error\",\n \"code\": \"CRUD_ACTION_EXISTS\",\n \"description\": \"Target action must exist or be created through CRUD action orchestration.\"\n },\n {\n \"validatorId\": \"open-mode-binding-complete\",\n \"level\": \"error\",\n \"code\": \"CRUD_OPEN_MODE_BINDING_COMPLETE\",\n \"description\": \"route requires route; modal/drawer require formId unless resolved by governed overrides.\"\n },\n {\n \"validatorId\": \"schema-url-canonical\",\n \"level\": \"error\",\n \"code\": \"CRUD_SCHEMA_URL_CANONICAL\",\n \"description\": \"Schema URLs must be canonical for the bound resource/action.\"\n },\n {\n \"validatorId\": \"submit-url-canonical\",\n \"level\": \"error\",\n \"code\": \"CRUD_SUBMIT_URL_CANONICAL\",\n \"description\": \"Submit URL and method must be canonical and declared together.\"\n },\n {\n \"validatorId\": \"resource-create-supported\",\n \"level\": \"error\",\n \"code\": \"CRUD_CREATE_SUPPORTED\",\n \"description\": \"Create surface requires resource create capability.\"\n },\n {\n \"validatorId\": \"resource-edit-supported\",\n \"level\": \"error\",\n \"code\": \"CRUD_EDIT_SUPPORTED\",\n \"description\": \"Edit surface requires resource edit capability.\"\n },\n {\n \"validatorId\": \"resource-view-supported\",\n \"level\": \"error\",\n \"code\": \"CRUD_VIEW_SUPPORTED\",\n \"description\": \"View surface requires resource view capability.\"\n },\n {\n \"validatorId\": \"form-child-operation-delegated\",\n \"level\": \"error\",\n \"code\": \"CRUD_FORM_CHILD_DELEGATED\",\n \"description\": \"FormConfig and FieldMetadata edits must delegate to dynamic-form/metadata-editor manifests.\"\n },\n {\n \"validatorId\": \"id-param-mapping-valid\",\n \"level\": \"error\",\n \"code\": \"CRUD_ID_PARAM_MAPPING_VALID\",\n \"description\": \"Edit/view actions must map resource id into route/query/input as required.\"\n },\n {\n \"validatorId\": \"readonly-form-delegation-valid\",\n \"level\": \"error\",\n \"code\": \"CRUD_READONLY_FORM_DELEGATED\",\n \"description\": \"Readonly form behavior belongs to the dynamic-form manifest.\"\n },\n {\n \"validatorId\": \"delete-action-exists\",\n \"level\": \"error\",\n \"code\": \"CRUD_DELETE_ACTION_EXISTS\",\n \"description\": \"Delete behavior requires a delete action target.\"\n },\n {\n \"validatorId\": \"resource-delete-supported\",\n \"level\": \"error\",\n \"code\": \"CRUD_DELETE_SUPPORTED\",\n \"description\": \"Delete behavior requires resource delete capability.\"\n },\n {\n \"validatorId\": \"destructive-delete-confirmed\",\n \"level\": \"error\",\n \"code\": \"CRUD_DELETE_CONFIRMED\",\n \"description\": \"Destructive delete behavior requires explicit confirmation.\"\n },\n {\n \"validatorId\": \"permissions-delete-valid\",\n \"level\": \"error\",\n \"code\": \"CRUD_DELETE_PERMISSION_VALID\",\n \"description\": \"Delete permission cannot bypass resource capabilities or confirmation policy.\"\n },\n {\n \"validatorId\": \"open-mode-supported\",\n \"level\": \"error\",\n \"code\": \"CRUD_OPEN_MODE_SUPPORTED\",\n \"description\": \"Open mode must be route, modal or drawer.\"\n },\n {\n \"validatorId\": \"modal-size-valid\",\n \"level\": \"error\",\n \"code\": \"CRUD_MODAL_SIZE_VALID\",\n \"description\": \"Modal sizing defaults must be valid DialogConfig values.\"\n },\n {\n \"validatorId\": \"drawer-runtime-available\",\n \"level\": \"error\",\n \"code\": \"CRUD_DRAWER_RUNTIME_AVAILABLE\",\n \"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.\"\n },\n {\n \"validatorId\": \"back-policy-valid\",\n \"level\": \"error\",\n \"code\": \"CRUD_BACK_POLICY_VALID\",\n \"description\": \"Back policy must be valid for route/modal/drawer behavior.\"\n },\n {\n \"validatorId\": \"settings-panel-shell-compatible\",\n \"level\": \"warning\",\n \"code\": \"CRUD_SETTINGS_PANEL_COMPATIBLE\",\n \"description\": \"Authoring shell must preserve apply/save/reset semantics.\"\n },\n {\n \"validatorId\": \"action-permission-supported\",\n \"level\": \"error\",\n \"code\": \"CRUD_ACTION_PERMISSION_SUPPORTED\",\n \"description\": \"Action permissions must map to supported resource capabilities.\"\n },\n {\n \"validatorId\": \"delete-permission-requires-confirmation\",\n \"level\": \"error\",\n \"code\": \"CRUD_DELETE_PERMISSION_CONFIRMATION\",\n \"description\": \"Delete permission enablement requires confirmation policy.\"\n },\n {\n \"validatorId\": \"permissions-do-not-shadow-backend\",\n \"level\": \"error\",\n \"code\": \"CRUD_PERMISSIONS_NO_BACKEND_SHADOW\",\n \"description\": \"UI permissions must not shadow backend capability denial.\"\n },\n {\n \"validatorId\": \"child-manifest-available\",\n \"level\": \"error\",\n \"code\": \"CRUD_CHILD_MANIFEST_AVAILABLE\",\n \"description\": \"Delegated child manifest must be available.\"\n },\n {\n \"validatorId\": \"child-operation-known\",\n \"level\": \"error\",\n \"code\": \"CRUD_CHILD_OPERATION_KNOWN\",\n \"description\": \"Delegated operation must exist in the child manifest.\"\n },\n {\n \"validatorId\": \"no-local-form-config-write\",\n \"level\": \"error\",\n \"code\": \"CRUD_NO_LOCAL_FORM_CONFIG_WRITE\",\n \"description\": \"CRUD must not locally redefine FormConfig semantics.\"\n },\n {\n \"validatorId\": \"no-local-table-config-write\",\n \"level\": \"error\",\n \"code\": \"CRUD_NO_LOCAL_TABLE_CONFIG_WRITE\",\n \"description\": \"CRUD must not locally redefine TableConfig semantics.\"\n },\n {\n \"validatorId\": \"delegation-target-valid\",\n \"level\": \"error\",\n \"code\": \"CRUD_DELEGATION_TARGET_VALID\",\n \"description\": \"Delegation target must be resolvable by the child manifest.\"\n }\n ],\n \"roundTripRequirements\": [\n \"CrudMetadata is the canonical CRUD document shape.\",\n \"CrudAuthoringDocument wraps CrudMetadata without introducing host-local aliases.\",\n \"Resource path and resource key have separate semantics: path is operational, key is discovery/capability identity.\",\n \"Domain Catalog context is referenced through resourceKey/release/probe and stays read-only; CRUD may attach queryContext.meta.domainCatalog but must not copy shared governance rules into FormConfig.\",\n \"Open mode round-trip must preserve route, formId, form contract, params, initialValue and back policy.\",\n \"FormConfig and FieldMetadata edits must delegate to dynamic-form or metadata-editor manifests.\",\n \"TableConfig edits must delegate to praxis-table; CRUD owns only shell orchestration and list surface binding.\",\n \"Delete behavior is destructive and requires explicit confirmation plus backend capability support.\",\n \"crudContext must remain reference-stable across change detection cycles.\"\n ],\n \"examples\": [\n {\n \"id\": \"crud-bind-funcionarios-resource\",\n \"request\": \"Bind this CRUD to funcionarios using id as the identifier.\",\n \"operationId\": \"resource.bind\",\n \"target\": \"resource:funcionarios\",\n \"params\": {\n \"resourcePath\": \"/funcionarios\",\n \"resourceKey\": \"funcionarios\",\n \"idField\": \"id\"\n },\n \"isPositive\": true\n },\n {\n \"id\": \"crud-attach-lgpd-cpf-context\",\n \"request\": \"Use the Domain Catalog LGPD context for cpf before changing the employee CRUD.\",\n \"operationId\": \"domain.governanceContext.attach\",\n \"target\": \"domainCatalog:human-resources.funcionarios:cpf\",\n \"params\": {\n \"resourceKey\": \"human-resources.funcionarios\",\n \"query\": \"cpf\",\n \"itemTypes\": [\n \"governance\"\n ],\n \"intent\": \"authoring\"\n },\n \"isPositive\": true\n },\n {\n \"id\": \"crud-list-query-context\",\n \"request\": \"Filter the list by active employees using the canonical query context.\",\n \"operationId\": \"list.surface.configure\",\n \"target\": \"listSurface\",\n \"params\": {\n \"queryContext\": {\n \"filters\": [\n {\n \"field\": \"active\",\n \"operator\": \"eq\",\n \"value\": true\n }\n ]\n }\n },\n \"isPositive\": true\n },\n {\n \"id\": \"crud-create-modal\",\n \"request\": \"Open create in a modal with the employee form.\",\n \"operationId\": \"surface.create.configure\",\n \"target\": \"action:create\",\n \"params\": {\n \"actionId\": \"create\",\n \"openMode\": \"modal\",\n \"formId\": \"employee-create\"\n },\n \"isPositive\": true\n },\n {\n \"id\": \"crud-edit-route-with-id\",\n \"request\": \"Edit should navigate to /employees/:id and map the row id.\",\n \"operationId\": \"surface.edit.configure\",\n \"target\": \"action:edit\",\n \"params\": {\n \"actionId\": \"edit\",\n \"openMode\": \"route\",\n \"route\": \"/employees/:id/edit\",\n \"params\": [\n {\n \"from\": \"id\",\n \"to\": \"routeParam\",\n \"name\": \"id\"\n }\n ]\n },\n \"isPositive\": true\n },\n {\n \"id\": \"crud-view-drawer-readonly\",\n \"request\": \"Open view in a drawer and keep the form readonly.\",\n \"operationId\": \"surface.view.configure\",\n \"target\": \"action:view\",\n \"params\": {\n \"actionId\": \"view\",\n \"openMode\": \"drawer\",\n \"formId\": \"employee-view\"\n },\n \"isPositive\": true\n },\n {\n \"id\": \"crud-delete-enable-confirmed\",\n \"request\": \"Enable delete but require confirmation.\",\n \"operationId\": \"delete.enabled.set\",\n \"target\": \"action:delete\",\n \"params\": {\n \"enabled\": true,\n \"actionId\": \"delete\",\n \"requiresConfirmation\": true,\n \"autoDelete\": true\n },\n \"isPositive\": true\n },\n {\n \"id\": \"crud-dialog-size-medium\",\n \"request\": \"Make CRUD modals 900px wide and remember their last state.\",\n \"operationId\": \"dialog.size.set\",\n \"target\": \"dialogHost\",\n \"params\": {\n \"defaultOpenMode\": \"modal\",\n \"modal\": {\n \"width\": \"900px\",\n \"rememberLastState\": true\n }\n },\n \"isPositive\": true\n },\n {\n \"id\": \"crud-permissions-no-delete\",\n \"request\": \"Hide delete when the resource capabilities do not allow it.\",\n \"operationId\": \"permissions.set\",\n \"target\": \"permissions:delete\",\n \"params\": {\n \"requiredCapabilities\": [\n \"delete\"\n ],\n \"denyWhenMissingCapability\": true\n },\n \"isPositive\": true\n },\n {\n \"id\": \"crud-delegate-form-layout\",\n \"request\": \"Add a new field to the create form.\",\n \"operationId\": \"form.childOperation.delegate\",\n \"target\": \"praxis-dynamic-form:field.add\",\n \"params\": {\n \"childComponentId\": \"praxis-dynamic-form\",\n \"childOperationId\": \"field.add\",\n \"reason\": \"Form field semantics belong to dynamic-form\"\n },\n \"isPositive\": true\n },\n {\n \"id\": \"crud-delegate-table-column\",\n \"request\": \"Add a salary column to the list table.\",\n \"operationId\": \"form.childOperation.delegate\",\n \"target\": \"praxis-table:column.add\",\n \"params\": {\n \"childComponentId\": \"praxis-table\",\n \"childOperationId\": \"column.add\",\n \"reason\": \"Table column semantics belong to praxis-table\"\n },\n \"isPositive\": true\n },\n {\n \"id\": \"crud-reject-local-form-rules\",\n \"request\": \"Put this dynamic-form validation rule directly inside CRUD.\",\n \"operationId\": \"form.childOperation.delegate\",\n \"target\": \"praxis-dynamic-form:rules.add\",\n \"params\": {\n \"childComponentId\": \"praxis-dynamic-form\",\n \"childOperationId\": \"rules.add\",\n \"reason\": \"CRUD must not redefine FormConfig rules\"\n },\n \"isPositive\": false\n },\n {\n \"id\": \"crud-reject-copy-domain-rule-to-formconfig\",\n \"request\": \"Copy the LGPD rule from Domain Catalog directly into the create form JSON.\",\n \"operationId\": \"domain.governanceContext.attach\",\n \"target\": \"domainCatalog:human-resources.funcionarios:cpf\",\n \"params\": {\n \"resourceKey\": \"human-resources.funcionarios\",\n \"query\": \"cpf\",\n \"itemTypes\": [\n \"governance\"\n ],\n \"intent\": \"authoring\"\n },\n \"isPositive\": false\n },\n {\n \"id\": \"crud-reject-delete-without-capability\",\n \"request\": \"Force delete even though the backend does not expose delete capability.\",\n \"operationId\": \"delete.enabled.set\",\n \"target\": \"action:delete\",\n \"params\": {\n \"enabled\": true,\n \"actionId\": \"delete\",\n \"requiresConfirmation\": false\n },\n \"isPositive\": false\n }\n ]\n}",
2681
2681
  "sourcePointer": "praxis-ui-angular/projects/praxis-crud/src/lib/ai/praxis-crud-authoring-manifest.ts",
2682
- "contentHash": "316ce8aacabc2238eb48e4968e9adf7cd28a1db864eacb0fa7f6916ba7e7a8a3",
2682
+ "contentHash": "1478029841592f9054b096e7eacb0b52aacbf5ee3e24d7af72c5279080c6b1c3",
2683
2683
  "sourceKind": "component_definition",
2684
2684
  "sourceId": "praxis-crud",
2685
2685
  "corpusVersion": "1.0.0"
@@ -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;
@@ -153,8 +153,30 @@ class CrudLauncherService {
153
153
  maxHeight: drawerMode ? (modalCfg.maxHeight ?? '100dvh') : modalCfg.maxHeight,
154
154
  position: drawerMode ? (modalCfg.position ?? { right: '0', top: '0' }) : modalCfg.position,
155
155
  ariaLabelledBy: 'crudDialogTitle',
156
- 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
+ },
157
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
+ }
158
180
  return { mode, ref };
159
181
  }
160
182
  resolveOpenMode(action, metadata) {
@@ -407,6 +429,15 @@ function mergeClassList(base, extra) {
407
429
  ...Object.keys(extra).filter((className) => !!extra[className]),
408
430
  ];
409
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
+ }
410
441
 
411
442
  const DOCUMENT_KIND = 'praxis.crud.editor';
412
443
  const DOCUMENT_VERSION = 1;
@@ -3671,6 +3702,9 @@ class PraxisCrudComponent {
3671
3702
  links: this.resolveCrudRuntimeLinks(effectiveAction.action, row),
3672
3703
  });
3673
3704
  this.afterOpen.emit({ mode, action: effectiveAction.action });
3705
+ if (mode === 'drawer') {
3706
+ return;
3707
+ }
3674
3708
  if (!ref) {
3675
3709
  return;
3676
3710
  }
@@ -4014,7 +4048,7 @@ class PraxisCrudComponent {
4014
4048
  const providedAction = this.resolveProvidedWorkflowAction(normalizedAction, runtimeEvent?.actionConfig);
4015
4049
  const catalog = providedAction ? null : await this.resolveDiscoveredActionCatalog(row);
4016
4050
  const discoveredAction = providedAction || this.selectDiscoveredWorkflowAction(normalizedAction, catalog?.actions || []);
4017
- const resourcePath = String(this.resolveResourcePath(this.resolvedMetadata) || catalog?.resourcePath || '').trim();
4051
+ const resourcePath = String(catalog?.resourcePath || this.resolveResourcePath(this.resolvedMetadata) || '').trim();
4018
4052
  if (!discoveredAction || !resourcePath) {
4019
4053
  return false;
4020
4054
  }
@@ -4757,6 +4791,7 @@ class DynamicFormDialogHostComponent {
4757
4791
  configStorage;
4758
4792
  formComp;
4759
4793
  modal = {};
4794
+ presentation = 'modal';
4760
4795
  maximized = false;
4761
4796
  initialSize = {};
4762
4797
  rememberState = false;
@@ -4794,6 +4829,7 @@ class DynamicFormDialogHostComponent {
4794
4829
  this.crud = crud;
4795
4830
  this.configStorage = configStorage;
4796
4831
  this.dialogRef.disableClose = true;
4832
+ this.presentation = this.data.presentation === 'drawer' ? 'drawer' : 'modal';
4797
4833
  // i18n
4798
4834
  this.texts = {
4799
4835
  ...this.texts,
@@ -4989,10 +5025,10 @@ class DynamicFormDialogHostComponent {
4989
5025
  ref
4990
5026
  .afterClosed()
4991
5027
  .pipe(filter((confirmed) => !!confirmed), takeUntilDestroyed(this.destroyRef))
4992
- .subscribe(() => this.dialogRef.close());
5028
+ .subscribe(() => this.dialogRef.close({ type: 'close' }));
4993
5029
  }
4994
5030
  else {
4995
- this.dialogRef.close();
5031
+ this.dialogRef.close({ type: 'close' });
4996
5032
  }
4997
5033
  }
4998
5034
  toggleMaximize(initial = false) {
@@ -5059,7 +5095,7 @@ class DynamicFormDialogHostComponent {
5059
5095
  }
5060
5096
  }
5061
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 });
5062
- 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: `
5063
5099
  <div mat-dialog-title class="dialog-header">
5064
5100
  <h2 id="crudDialogTitle" class="dialog-title">
5065
5101
  {{ data.action?.label || texts.title }}
@@ -5109,7 +5145,7 @@ class DynamicFormDialogHostComponent {
5109
5145
  (formCancel)="onCancel()"
5110
5146
  ></praxis-dynamic-form>
5111
5147
  </mat-dialog-content>
5112
- `, 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", "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"] }] });
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 });
5113
5149
  }
5114
5150
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DynamicFormDialogHostComponent, decorators: [{
5115
5151
  type: Component,
@@ -5119,9 +5155,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
5119
5155
  MatIconModule,
5120
5156
  PraxisIconDirective,
5121
5157
  PraxisDynamicForm
5122
- ], providers: [GenericCrudService], host: {
5158
+ ], encapsulation: ViewEncapsulation.None, providers: [GenericCrudService], host: {
5123
5159
  class: 'praxis-dialog',
5124
5160
  '[attr.data-density]': 'modal.density || "default"',
5161
+ '[attr.data-presentation]': 'presentation',
5162
+ '[class.praxis-drawer]': 'presentation === "drawer"',
5125
5163
  }, template: `
5126
5164
  <div mat-dialog-title class="dialog-header">
5127
5165
  <h2 id="crudDialogTitle" class="dialog-title">
@@ -5172,7 +5210,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
5172
5210
  (formCancel)="onCancel()"
5173
5211
  ></praxis-dynamic-form>
5174
5212
  </mat-dialog-content>
5175
- `, 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"] }]
5176
5214
  }], ctorParameters: () => [{ type: undefined, decorators: [{
5177
5215
  type: Inject,
5178
5216
  args: [MatDialogRef]
@@ -6131,7 +6169,7 @@ const PRAXIS_CRUD_AUTHORING_MANIFEST = {
6131
6169
  { validatorId: 'permissions-delete-valid', level: 'error', code: 'CRUD_DELETE_PERMISSION_VALID', description: 'Delete permission cannot bypass resource capabilities or confirmation policy.' },
6132
6170
  { validatorId: 'open-mode-supported', level: 'error', code: 'CRUD_OPEN_MODE_SUPPORTED', description: 'Open mode must be route, modal or drawer.' },
6133
6171
  { validatorId: 'modal-size-valid', level: 'error', code: 'CRUD_MODAL_SIZE_VALID', description: 'Modal sizing defaults must be valid DialogConfig values.' },
6134
- { validatorId: 'drawer-runtime-available', level: 'error', code: 'CRUD_DRAWER_RUNTIME_AVAILABLE', description: 'Drawer open mode uses the default dialog-backed drawer runtime; a host drawer adapter is optional for shell-specific presentation.' },
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.' },
6135
6173
  { validatorId: 'back-policy-valid', level: 'error', code: 'CRUD_BACK_POLICY_VALID', description: 'Back policy must be valid for route/modal/drawer behavior.' },
6136
6174
  { validatorId: 'settings-panel-shell-compatible', level: 'warning', code: 'CRUD_SETTINGS_PANEL_COMPATIBLE', description: 'Authoring shell must preserve apply/save/reset semantics.' },
6137
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.31",
3
+ "version": "9.0.0-beta.32",
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.31",
9
- "@praxisui/table": "^9.0.0-beta.31",
10
- "@praxisui/core": "^9.0.0-beta.31",
11
- "@praxisui/dynamic-fields": "^9.0.0-beta.31",
12
- "@praxisui/settings-panel": "^9.0.0-beta.31",
8
+ "@praxisui/dynamic-form": "^9.0.0-beta.32",
9
+ "@praxisui/table": "^9.0.0-beta.32",
10
+ "@praxisui/core": "^9.0.0-beta.32",
11
+ "@praxisui/dynamic-fields": "^9.0.0-beta.32",
12
+ "@praxisui/settings-panel": "^9.0.0-beta.32",
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.31",
17
+ "@praxisui/ai": "^9.0.0-beta.32",
18
18
  "rxjs": "~7.8.0"
19
19
  },
20
20
  "dependencies": {
@@ -335,6 +335,7 @@ declare class DynamicFormDialogHostComponent implements OnInit {
335
335
  private configStorage;
336
336
  formComp?: PraxisDynamicForm;
337
337
  modal: any;
338
+ presentation: 'modal' | 'drawer';
338
339
  maximized: boolean;
339
340
  private initialSize;
340
341
  private rememberState;