@praxisui/manual-form 10.0.0-rc.40 → 10.0.0-rc.42

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-10-26T18:09:20.136Z",
3
+ "generatedAt": "2026-11-01T13:59:56.156Z",
4
4
  "packageName": "@praxisui/manual-form",
5
- "packageVersion": "10.0.0-rc.40",
5
+ "packageVersion": "10.0.0-rc.42",
6
6
  "sourceRegistry": "praxis-component-registry-ingestion",
7
7
  "sourceRegistryVersion": "1.0.0",
8
8
  "componentCount": 1,
@@ -1,4 +1,4 @@
1
- import { ensureIds, DynamicFormService, ASYNC_CONFIG_STORAGE, RULE_PROPERTY_SCHEMA, deepMerge, resolveControlTypeAlias, FieldControlType, normalizeControlTypeKey, PraxisIconButtonComponent, FormHooksRegistry, ComponentKeyService, FIELD_SELECTOR_REGISTRY_DISABLE_DEFAULTS, DEFAULT_FIELD_SELECTOR_CONTROL_TYPE_MAP, FieldSelectorRegistry, providePraxisI18n, PraxisI18nService, API_URL, ComponentMetadataRegistry } from '@praxisui/core';
1
+ import { ensureIds, DynamicFormService, ASYNC_CONFIG_STORAGE, RULE_PROPERTY_SCHEMA, deepMerge, PRAXIS_RUNTIME_FORM_VALUE_PROPOSAL_SCHEMA_VERSION, resolveControlTypeAlias, FieldControlType, normalizeControlTypeKey, PraxisIconButtonComponent, FormHooksRegistry, ComponentKeyService, FIELD_SELECTOR_REGISTRY_DISABLE_DEFAULTS, DEFAULT_FIELD_SELECTOR_CONTROL_TYPE_MAP, FieldSelectorRegistry, PraxisRuntimeFormValueSessionJournal, previewRuntimeFormValueProposal, applyRuntimeFormValueProposal, undoRuntimeFormValueApply, instanceKeyFor, evaluateFieldAccess, providePraxisI18n, PraxisI18nService, API_URL, ComponentMetadataRegistry } from '@praxisui/core';
2
2
  import * as i0 from '@angular/core';
3
3
  import { inject, Optional, Inject, Injectable, input, output, ChangeDetectionStrategy, Component, Input, InjectionToken, isDevMode, EventEmitter, HostListener, ViewChild, Output, ChangeDetectorRef, DestroyRef, PLATFORM_ID, effect, ContentChildren, signal, computed, Directive, ENVIRONMENT_INITIALIZER } from '@angular/core';
4
4
  import { BehaviorSubject, firstValueFrom, debounceTime, fromEvent, of } from 'rxjs';
@@ -459,6 +459,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
459
459
 
460
460
  class ManualFormActionsComponent {
461
461
  actions = input(...(ngDevMode ? [undefined, { debugName: "actions" }] : /* istanbul ignore next */ []));
462
+ submitDisabled = input(false, ...(ngDevMode ? [{ debugName: "submitDisabled" }] : /* istanbul ignore next */ []));
462
463
  trackByFn = null;
463
464
  actionClick = output();
464
465
  isVisible(action) {
@@ -473,7 +474,7 @@ class ManualFormActionsComponent {
473
474
  }
474
475
  }
475
476
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: ManualFormActionsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
476
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: ManualFormActionsComponent, isStandalone: true, selector: "praxis-manual-form-actions", inputs: { actions: { classPropertyName: "actions", publicName: "actions", isSignal: true, isRequired: false, transformFunction: null }, trackByFn: { classPropertyName: "trackByFn", publicName: "trackByFn", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { actionClick: "actionClick" }, ngImport: i0, template: `
477
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: ManualFormActionsComponent, isStandalone: true, selector: "praxis-manual-form-actions", inputs: { actions: { classPropertyName: "actions", publicName: "actions", isSignal: true, isRequired: false, transformFunction: null }, submitDisabled: { classPropertyName: "submitDisabled", publicName: "submitDisabled", isSignal: true, isRequired: false, transformFunction: null }, trackByFn: { classPropertyName: "trackByFn", publicName: "trackByFn", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { actionClick: "actionClick" }, ngImport: i0, template: `
477
478
  @if (actions(); as layout) {
478
479
  <footer class="pdx-manual-form__actions">
479
480
  <div class="pdx-manual-form__actions-secondary">
@@ -502,7 +503,7 @@ class ManualFormActionsComponent {
502
503
  <div class="pdx-manual-form__actions-primary">
503
504
  @if (layout.submit; as submitBtn) {
504
505
  @if (isVisible(submitBtn)) {
505
- <button type="submit" class="pdx-btn pdx-btn--primary" [disabled]="submitBtn.disabled" (click)="emit('submit', submitBtn)">
506
+ <button type="submit" class="pdx-btn pdx-btn--primary" [disabled]="submitBtn.disabled || submitDisabled()" (click)="emit('submit', submitBtn)">
506
507
  {{ submitBtn.label || 'Salvar' }}
507
508
  </button>
508
509
  }
@@ -543,7 +544,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
543
544
  <div class="pdx-manual-form__actions-primary">
544
545
  @if (layout.submit; as submitBtn) {
545
546
  @if (isVisible(submitBtn)) {
546
- <button type="submit" class="pdx-btn pdx-btn--primary" [disabled]="submitBtn.disabled" (click)="emit('submit', submitBtn)">
547
+ <button type="submit" class="pdx-btn pdx-btn--primary" [disabled]="submitBtn.disabled || submitDisabled()" (click)="emit('submit', submitBtn)">
547
548
  {{ submitBtn.label || 'Salvar' }}
548
549
  </button>
549
550
  }
@@ -552,7 +553,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
552
553
  </footer>
553
554
  }
554
555
  `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block}.pdx-manual-form__actions{display:flex;justify-content:space-between;align-items:center;gap:1rem;margin-top:2rem;flex-wrap:wrap}.pdx-manual-form__actions-secondary,.pdx-manual-form__actions-primary{display:flex;gap:.5rem}.pdx-btn{min-height:36px;padding:0 14px;border-radius:8px;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface);color:var(--md-sys-color-on-surface);cursor:pointer;transition:background-color .18s ease,border-color .18s ease,color .18s ease}.pdx-btn:hover{background:var(--md-sys-color-surface-container)}.pdx-btn:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.pdx-btn:disabled{opacity:.6;cursor:not-allowed}.pdx-btn--ghost{background:transparent;border-color:var(--md-sys-color-outline-variant);color:var(--md-sys-color-on-surface-variant)}.pdx-btn--primary{background:var(--md-sys-color-primary);color:var(--md-sys-color-on-primary);border-color:var(--md-sys-color-primary)}.pdx-btn--primary:hover{background:var(--md-sys-color-primary-container);border-color:var(--md-sys-color-primary-container);color:var(--md-sys-color-on-primary-container)}\n"] }]
555
- }], propDecorators: { actions: [{ type: i0.Input, args: [{ isSignal: true, alias: "actions", required: false }] }], trackByFn: [{
556
+ }], propDecorators: { actions: [{ type: i0.Input, args: [{ isSignal: true, alias: "actions", required: false }] }], submitDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "submitDisabled", required: false }] }], trackByFn: [{
556
557
  type: Input
557
558
  }], actionClick: [{ type: i0.Output, args: ["actionClick"] }] } });
558
559
 
@@ -1146,19 +1147,92 @@ class ManualFormAiAdapter extends BaseAiAdapter {
1146
1147
  .filter((field) => typeof field.name === 'string' && !!field.name.trim());
1147
1148
  }
1148
1149
  getAuthoringContext() {
1150
+ const autoSaveEnabled = !!this.host.enableAutoSave();
1151
+ const targetIdentity = this.getRuntimeValueTargetIdentity();
1152
+ const eligibility = this.getRuntimeValueEligibility();
1153
+ const canAssistRuntimeValues = !autoSaveEnabled && (eligibility ? eligibility.eligible : false);
1149
1154
  return {
1150
1155
  authoringManifestRef: 'PRAXIS_MANUAL_FORM_AUTHORING_MANIFEST',
1151
1156
  runtimeAuthoringPolicy: {
1152
- mode: 'agentic-authoring',
1157
+ mode: this.host.enableCustomization() ? 'agentic-authoring' : 'runtime-value-assistance',
1153
1158
  enableCustomization: !!this.host.enableCustomization(),
1154
1159
  canApplyLocalPatch: false,
1155
- reason: 'praxis-manual-form ainda exige componentEditPlan manifest-backed antes de aplicar patch local pelo copiloto.',
1160
+ canAssistRuntimeValues,
1161
+ autoSaveEnabled,
1162
+ reason: autoSaveEnabled
1163
+ ? 'praxis-manual-form com enableAutoSave=true não aplica rascunho transitório automaticamente para evitar persistência implícita.'
1164
+ : eligibility?.blockMessage
1165
+ ? eligibility.blockMessage
1166
+ : 'praxis-manual-form ainda exige componentEditPlan manifest-backed antes de aplicar patch local pelo copiloto.',
1156
1167
  },
1168
+ ...(targetIdentity
1169
+ ? {
1170
+ runtimeValueAssistance: {
1171
+ enabled: canAssistRuntimeValues,
1172
+ targetIdentity,
1173
+ autoSaveEnabled,
1174
+ hasPendingReactiveDeterminations: eligibility?.hasPendingReactiveDeterminations ?? false,
1175
+ hasPendingAsyncValidators: eligibility?.hasPendingAsyncValidators ?? false,
1176
+ writableFields: eligibility?.writableFields ?? [],
1177
+ nonOverwritableFields: eligibility?.nonOverwritableFields ?? [],
1178
+ ...(this.resolveGovernedSchemaPayload(targetIdentity)
1179
+ ? { governedSchema: this.resolveGovernedSchemaPayload(targetIdentity) }
1180
+ : {}),
1181
+ defaultApplyMode: 'empty-only',
1182
+ },
1183
+ }
1184
+ : {}),
1157
1185
  domainCatalog: {
1158
1186
  recommendedAuthoringFlow: 'component_authoring',
1159
1187
  },
1160
1188
  };
1161
1189
  }
1190
+ resolveGovernedSchemaPayload(targetIdentity) {
1191
+ const rawGoverned = this.host.governedSchema?.();
1192
+ if (!rawGoverned) {
1193
+ return null;
1194
+ }
1195
+ if (Array.isArray(rawGoverned)) {
1196
+ const properties = {};
1197
+ for (const item of rawGoverned) {
1198
+ if (item && typeof item === 'object' && typeof item.name === 'string') {
1199
+ properties[item.name] = item;
1200
+ }
1201
+ }
1202
+ return {
1203
+ ...(targetIdentity.schemaHash ? { 'x-schema-hash': targetIdentity.schemaHash } : {}),
1204
+ properties,
1205
+ };
1206
+ }
1207
+ if (typeof rawGoverned === 'object') {
1208
+ return {
1209
+ ...(targetIdentity.schemaHash ? { 'x-schema-hash': targetIdentity.schemaHash } : {}),
1210
+ ...rawGoverned,
1211
+ };
1212
+ }
1213
+ return null;
1214
+ }
1215
+ getRuntimeValueTargetIdentity() {
1216
+ return this.host.getRuntimeValueTargetIdentity?.() ?? null;
1217
+ }
1218
+ getRuntimeValueEligibility() {
1219
+ return this.host.getRuntimeValueEligibility?.() ?? null;
1220
+ }
1221
+ previewRuntimeValues(proposal, options) {
1222
+ return this.host.previewRuntimeValues?.(proposal, options) ?? null;
1223
+ }
1224
+ async applyRuntimeValues(request) {
1225
+ if (!this.host.applyRuntimeValues) {
1226
+ return null;
1227
+ }
1228
+ return await this.host.applyRuntimeValues(request);
1229
+ }
1230
+ async undoRuntimeValues(receiptId) {
1231
+ if (!this.host.undoRuntimeValues) {
1232
+ return null;
1233
+ }
1234
+ return await this.host.undoRuntimeValues(receiptId);
1235
+ }
1162
1236
  createSnapshot() {
1163
1237
  return this.getCurrentConfig();
1164
1238
  }
@@ -1241,6 +1315,10 @@ class ManualFormAgenticAuthoringTurnFlow {
1241
1315
  this.aiApi = aiApi;
1242
1316
  }
1243
1317
  async submit(request) {
1318
+ if (request.action?.kind === 'runtime-form-value-undo' ||
1319
+ request.action?.id === 'undo-runtime-values') {
1320
+ return this.apply(request);
1321
+ }
1244
1322
  const prompt = (request.prompt ?? '').trim();
1245
1323
  if (!prompt) {
1246
1324
  return {
@@ -1285,7 +1363,115 @@ class ManualFormAgenticAuthoringTurnFlow {
1285
1363
  })));
1286
1364
  return this.toTurnResult(this.compileAdapterResponse(response), request);
1287
1365
  }
1288
- async apply(_request) {
1366
+ async apply(request) {
1367
+ const runtimeAdapter = this.adapter;
1368
+ if (request.action?.kind === 'runtime-form-value-undo' ||
1369
+ request.action?.id === 'undo-runtime-values') {
1370
+ const actionHints = this.toRecord(request.action?.contextHints);
1371
+ const receiptId = typeof actionHints?.['receiptId'] === 'string'
1372
+ ? actionHints['receiptId']
1373
+ : typeof request.action?.value === 'string'
1374
+ ? request.action.value
1375
+ : undefined;
1376
+ const undoReceipt = await runtimeAdapter.undoRuntimeValues?.(receiptId);
1377
+ if (!undoReceipt || undoReceipt.revertedFields.length === 0) {
1378
+ const preservedMsg = undoReceipt && undoReceipt.preservedManualFields.length > 0
1379
+ ? `Nenhum campo foi revertido porque ${undoReceipt.preservedManualFields.length} campo(s) foram editados manualmente após a aplicação.`
1380
+ : 'Não há preenchimento pendente para desfazer nesta instância.';
1381
+ return {
1382
+ state: 'success',
1383
+ phase: 'summarize',
1384
+ assistantMessage: preservedMsg,
1385
+ statusText: preservedMsg,
1386
+ canApply: false,
1387
+ pendingPatch: null,
1388
+ diagnostics: undoReceipt
1389
+ ? { runtimeValueUndoReceipt: undoReceipt }
1390
+ : undefined,
1391
+ };
1392
+ }
1393
+ const manualSuffix = undoReceipt.preservedManualFields.length > 0
1394
+ ? ` (${undoReceipt.preservedManualFields.length} campo(s) editado(s) manualmente foram preservados).`
1395
+ : '.';
1396
+ const message = `Preenchimento desfeito em ${undoReceipt.revertedFields.length} campo(s)${manualSuffix}`;
1397
+ return {
1398
+ state: 'success',
1399
+ phase: 'summarize',
1400
+ assistantMessage: message,
1401
+ statusText: message,
1402
+ canApply: false,
1403
+ pendingPatch: null,
1404
+ preview: {
1405
+ kind: 'runtime-form-value-undo-receipt',
1406
+ undoReceipt,
1407
+ },
1408
+ diagnostics: {
1409
+ runtimeValueUndoReceipt: undoReceipt,
1410
+ },
1411
+ };
1412
+ }
1413
+ const runtimeProposal = this.extractRuntimeValueProposal(request.runtimeValueProposal) ??
1414
+ this.extractRuntimeValueProposal(request.pendingPatch);
1415
+ if (runtimeProposal) {
1416
+ const actionHints = this.toRecord(request.action?.contextHints);
1417
+ const selectedFieldPaths = Array.isArray(actionHints?.['selectedFieldPaths'])
1418
+ ? actionHints['selectedFieldPaths'].filter((item) => typeof item === 'string' && item.trim().length > 0)
1419
+ : undefined;
1420
+ const applyModeCandidate = actionHints?.['applyMode'];
1421
+ const applyMode = applyModeCandidate === 'empty-only' || applyModeCandidate === 'selected-fields'
1422
+ ? applyModeCandidate
1423
+ : undefined;
1424
+ const receipt = await runtimeAdapter.applyRuntimeValues?.({
1425
+ proposal: runtimeProposal,
1426
+ selectedFieldPaths,
1427
+ applyMode,
1428
+ });
1429
+ if (!receipt || receipt.appliedFields.length === 0) {
1430
+ const blockMessage = receipt?.warnings?.[receipt.warnings.length - 1] ??
1431
+ 'A proposta de preenchimento do formulário manual não pôde ser aplicada.';
1432
+ return {
1433
+ state: 'clarification',
1434
+ phase: 'clarify',
1435
+ assistantMessage: blockMessage,
1436
+ statusText: blockMessage,
1437
+ canApply: false,
1438
+ pendingPatch: null,
1439
+ runtimeValueProposal: runtimeProposal,
1440
+ runtimeValueReceipt: receipt ?? null,
1441
+ };
1442
+ }
1443
+ const appliedLabels = receipt.appliedFields
1444
+ .map((field) => field.label || field.fieldPath)
1445
+ .join(', ');
1446
+ return {
1447
+ state: 'success',
1448
+ phase: 'summarize',
1449
+ assistantMessage: `Preenchimento transitório aplicado em ${receipt.appliedFields.length} campo(s) (${appliedLabels}). Os dados permanecem não salvos até o envio explícito do formulário.`,
1450
+ statusText: `${receipt.appliedFields.length} campo(s) preenchido(s) no formulário manual.`,
1451
+ canApply: false,
1452
+ pendingPatch: null,
1453
+ runtimeValueProposal: runtimeProposal,
1454
+ runtimeValueReceipt: receipt,
1455
+ preview: {
1456
+ kind: 'runtime-form-value-receipt',
1457
+ receipt,
1458
+ },
1459
+ quickReplies: receipt.canUndo
1460
+ ? [
1461
+ {
1462
+ id: 'undo-runtime-values',
1463
+ label: 'Desfazer preenchimento',
1464
+ prompt: 'Desfazer preenchimento aplicado',
1465
+ kind: 'runtime-form-value-undo',
1466
+ icon: 'undo',
1467
+ contextHints: {
1468
+ receiptId: receipt.receiptId,
1469
+ },
1470
+ },
1471
+ ]
1472
+ : [],
1473
+ };
1474
+ }
1289
1475
  return {
1290
1476
  state: 'error',
1291
1477
  phase: 'apply',
@@ -1324,20 +1510,82 @@ class ManualFormAgenticAuthoringTurnFlow {
1324
1510
  errorText: 'Resposta vazia da IA.',
1325
1511
  };
1326
1512
  }
1513
+ const runtimeProposal = this.extractRuntimeValueProposal(response['runtimeValueProposal']) ?? this.extractRuntimeValueProposal(response.patch);
1514
+ if (runtimeProposal) {
1515
+ const runtimeAdapter = this.adapter;
1516
+ const preview = runtimeAdapter.previewRuntimeValues?.(runtimeProposal) ?? null;
1517
+ const canApply = Boolean(preview?.canApply);
1518
+ if (!canApply) {
1519
+ const blockMessage = preview?.blockMessage ||
1520
+ this.sanitizeBlockedAssistantMessage(response.message ||
1521
+ response.explanation ||
1522
+ 'A proposta de preenchimento do formulário manual está bloqueada no estado atual.');
1523
+ return {
1524
+ state: 'clarification',
1525
+ phase: 'clarify',
1526
+ sessionId: response.sessionId ?? request.sessionId,
1527
+ observationId: response.observationId ?? request.observationId ?? null,
1528
+ assistantMessage: blockMessage,
1529
+ statusText: blockMessage,
1530
+ canApply: false,
1531
+ pendingPatch: null,
1532
+ runtimeValueProposal: runtimeProposal,
1533
+ preview: {
1534
+ kind: 'runtime-form-value-proposal',
1535
+ proposal: runtimeProposal,
1536
+ ...(preview ? { runtimePreview: preview } : {}),
1537
+ },
1538
+ diagnostics: {
1539
+ ...(preview
1540
+ ? {
1541
+ runtimeValuePreview: preview,
1542
+ }
1543
+ : {}),
1544
+ },
1545
+ };
1546
+ }
1547
+ const summaryMessage = response.message ||
1548
+ response.explanation ||
1549
+ `Proposta de preenchimento pronta para revisão (${preview?.applicableCount ?? runtimeProposal.assignments.length} campo(s) aplicável(is)).`;
1550
+ return {
1551
+ state: 'review',
1552
+ phase: 'review',
1553
+ sessionId: response.sessionId ?? request.sessionId,
1554
+ observationId: response.observationId ?? request.observationId ?? null,
1555
+ assistantMessage: summaryMessage,
1556
+ statusText: summaryMessage,
1557
+ canApply: true,
1558
+ pendingPatch: runtimeProposal,
1559
+ runtimeValueProposal: runtimeProposal,
1560
+ preview: {
1561
+ kind: 'runtime-form-value-proposal',
1562
+ proposal: runtimeProposal,
1563
+ ...(preview ? { runtimePreview: preview } : {}),
1564
+ },
1565
+ diagnostics: {
1566
+ ...(preview
1567
+ ? {
1568
+ runtimeValuePreview: preview,
1569
+ }
1570
+ : {}),
1571
+ },
1572
+ };
1573
+ }
1327
1574
  if (response.type === 'clarification') {
1575
+ const assistantMessage = this.sanitizeBlockedAssistantMessage(response.message || 'Preciso de mais detalhes para continuar.');
1328
1576
  return {
1329
1577
  state: 'clarification',
1330
1578
  phase: 'clarify',
1331
1579
  sessionId: response.sessionId ?? request.sessionId,
1332
1580
  observationId: response.observationId ?? request.observationId ?? null,
1333
- assistantMessage: response.message || 'Preciso de mais detalhes para continuar.',
1581
+ assistantMessage,
1334
1582
  clarificationQuestions: this.toClarificationQuestions(response),
1335
1583
  quickReplies: this.toQuickReplies(response),
1336
1584
  canApply: false,
1337
1585
  };
1338
1586
  }
1339
1587
  if (response.type === 'info') {
1340
- const message = response.message || response.explanation || 'Informacao gerada.';
1588
+ const message = this.sanitizeBlockedAssistantMessage(response.message || response.explanation || 'Informacao gerada.');
1341
1589
  return {
1342
1590
  state: 'success',
1343
1591
  phase: 'summarize',
@@ -1530,6 +1778,27 @@ class ManualFormAgenticAuthoringTurnFlow {
1530
1778
  },
1531
1779
  };
1532
1780
  }
1781
+ sanitizeBlockedAssistantMessage(message) {
1782
+ const trimmed = (message ?? '').trim();
1783
+ if (!trimmed) {
1784
+ return 'Esta operação não pôde ser executada automaticamente neste turno. Revise o escopo ou informe os dados desejados.';
1785
+ }
1786
+ const kept = trimmed
1787
+ .split(/(?<=[.!?])\s+/)
1788
+ .map((part) => part.trim())
1789
+ .filter((part) => part.length > 0 && !this.isFalseExecutionPromiseSentence(part));
1790
+ if (kept.length === 0) {
1791
+ return 'Esta operação não pôde ser executada automaticamente neste turno. Revise o escopo ou informe os dados desejados.';
1792
+ }
1793
+ return kept.join(' ');
1794
+ }
1795
+ isFalseExecutionPromiseSentence(sentence) {
1796
+ return (/^(pronto|feito|conclu[ií]do|done|ready)[.!]*$/i.test(sentence) ||
1797
+ /\b(preenchi|preenchemos|preenchido[s]?|apliquei|aplicamos|salvei|salvamos)\b.*\b(campo[s]?|formul[aá]rio|altera[cç][oõ]es|configura[cç][aã]o|valores)\b/i.test(sentence) ||
1798
+ /\b(confirme|clique)\s+para\s+(aplicar|salvar|preencher|materializar)\b/i.test(sentence) ||
1799
+ /\bdeseja\s+(aplicar|salvar|materializar)\s+(a\s+configura[cç][aã]o|o\s+patch|as\s+altera[cç][oõ]es|os\s+valores)\b/i.test(sentence) ||
1800
+ /\bposso\s+aplicar\s+agora\b/i.test(sentence));
1801
+ }
1533
1802
  optionalJsonObject(value) {
1534
1803
  if (value === undefined || value === null) {
1535
1804
  return undefined;
@@ -1564,6 +1833,16 @@ class ManualFormAgenticAuthoringTurnFlow {
1564
1833
  ? value
1565
1834
  : null;
1566
1835
  }
1836
+ extractRuntimeValueProposal(candidate) {
1837
+ const record = this.toRecord(candidate);
1838
+ if (!record ||
1839
+ record['schemaVersion'] !== PRAXIS_RUNTIME_FORM_VALUE_PROPOSAL_SCHEMA_VERSION ||
1840
+ !Array.isArray(record['assignments']) ||
1841
+ !this.toRecord(record['targetIdentity'])) {
1842
+ return null;
1843
+ }
1844
+ return record;
1845
+ }
1567
1846
  }
1568
1847
 
1569
1848
  const MANUAL_FORM_SELECTOR_TO_CONTROL_TYPE = new InjectionToken('MANUAL_FORM_SELECTOR_TO_CONTROL_TYPE');
@@ -2036,6 +2315,7 @@ class ManualFormComponent {
2036
2315
  showActions = input(true, ...(ngDevMode ? [{ debugName: "showActions" }] : /* istanbul ignore next */ []));
2037
2316
  enableAutoSave = input(true, ...(ngDevMode ? [{ debugName: "enableAutoSave" }] : /* istanbul ignore next */ []));
2038
2317
  componentInstanceId = input(...(ngDevMode ? [undefined, { debugName: "componentInstanceId" }] : /* istanbul ignore next */ []));
2318
+ showAiAssistant = input(true, ...(ngDevMode ? [{ debugName: "showAiAssistant" }] : /* istanbul ignore next */ []));
2039
2319
  // Allows editor affordances (e.g., opening metadata editor on interactions)
2040
2320
  enableCustomization = input(false, ...(ngDevMode ? [{ debugName: "enableCustomization" }] : /* istanbul ignore next */ []));
2041
2321
  persistenceOptions = input(...(ngDevMode ? [undefined, { debugName: "persistenceOptions" }] : /* istanbul ignore next */ []));
@@ -2044,6 +2324,11 @@ class ManualFormComponent {
2044
2324
  usePathNames = input(false, ...(ngDevMode ? [{ debugName: "usePathNames" }] : /* istanbul ignore next */ []));
2045
2325
  // Debounce interval for autosave (ms). Only used when enableAutoSave is true.
2046
2326
  autoSaveDebounceMs = input(800, ...(ngDevMode ? [{ debugName: "autoSaveDebounceMs" }] : /* istanbul ignore next */ []));
2327
+ resourcePath = input(...(ngDevMode ? [undefined, { debugName: "resourcePath" }] : /* istanbul ignore next */ []));
2328
+ governedSchema = input(null, ...(ngDevMode ? [{ debugName: "governedSchema" }] : /* istanbul ignore next */ []));
2329
+ schemaHash = input(...(ngDevMode ? [undefined, { debugName: "schemaHash" }] : /* istanbul ignore next */ []));
2330
+ mode = input('create', ...(ngDevMode ? [{ debugName: "mode" }] : /* istanbul ignore next */ []));
2331
+ entityId = input(null, ...(ngDevMode ? [{ debugName: "entityId" }] : /* istanbul ignore next */ []));
2047
2332
  submitted = output();
2048
2333
  saved = output();
2049
2334
  resetEvent = output({ alias: 'reset' });
@@ -2071,6 +2356,12 @@ class ManualFormComponent {
2071
2356
  aiAssistantStateSubscription = null;
2072
2357
  formGroup = new FormGroup({});
2073
2358
  registeredDirectives = [];
2359
+ runtimeValueJournal = new PraxisRuntimeFormValueSessionJournal();
2360
+ runtimeValueRevision = 0;
2361
+ runtimeValueTrackedForm = null;
2362
+ runtimeValueStatusSub;
2363
+ runtimeValueTrackedControls = new Map();
2364
+ suppressRuntimeValueTrackingDepth = 0;
2074
2365
  constructor() {
2075
2366
  // Host-typed mode: if a FormGroupDirective is present, adopt its FormGroup without monkey patches.
2076
2367
  if (this.hostFormGroupDirective) {
@@ -2120,9 +2411,16 @@ class ManualFormComponent {
2120
2411
  this.metadataSubscription?.unsubscribe();
2121
2412
  this.toolbarOverlayRef?.dispose();
2122
2413
  this.outsideClickSubscription?.unsubscribe();
2414
+ this.clearRuntimeValueControlSubscriptions();
2123
2415
  this.assistantSessions.removeContextSession(this.buildAiAssistantContextSnapshot().identity);
2124
2416
  this.aiAssistantStateSubscription?.unsubscribe();
2125
2417
  }
2418
+ get effectiveFormIsValid() {
2419
+ this.syncHostFormGroupReference();
2420
+ return (!this.formGroup.invalid &&
2421
+ !this.formGroup.pending &&
2422
+ this.formGroup.status === 'VALID');
2423
+ }
2126
2424
  // =============================
2127
2425
  // ControlContainer interface
2128
2426
  // =============================
@@ -2234,14 +2532,35 @@ class ManualFormComponent {
2234
2532
  }
2235
2533
  }
2236
2534
  async handleSubmit() {
2535
+ this.syncHostFormGroupReference();
2237
2536
  if (!this.instance) {
2238
2537
  return;
2239
2538
  }
2539
+ if (this.formGroup.invalid ||
2540
+ this.formGroup.pending ||
2541
+ this.formGroup.status !== 'VALID') {
2542
+ this.formGroup.markAllAsTouched();
2543
+ if (!this.formGroup.pending) {
2544
+ this.formGroup.updateValueAndValidity({ onlySelf: false, emitEvent: false });
2545
+ }
2546
+ this.cdr.markForCheck();
2547
+ return;
2548
+ }
2240
2549
  const value = this.formGroup.getRawValue();
2241
2550
  const beforeSubmitOk = await this.runHooks('beforeSubmit', { value });
2242
2551
  if (!beforeSubmitOk) {
2243
2552
  return;
2244
2553
  }
2554
+ if (this.formGroup.invalid ||
2555
+ this.formGroup.pending ||
2556
+ this.formGroup.status !== 'VALID') {
2557
+ this.formGroup.markAllAsTouched();
2558
+ if (!this.formGroup.pending) {
2559
+ this.formGroup.updateValueAndValidity({ onlySelf: false, emitEvent: false });
2560
+ }
2561
+ this.cdr.markForCheck();
2562
+ return;
2563
+ }
2245
2564
  if (this.enableAutoSave()) {
2246
2565
  this.instance.saveDraft(value);
2247
2566
  }
@@ -2380,8 +2699,8 @@ class ManualFormComponent {
2380
2699
  this.cdr.markForCheck();
2381
2700
  });
2382
2701
  }
2383
- onAiAssistantApply() {
2384
- this.aiAssistantController?.apply().subscribe((state) => {
2702
+ onAiAssistantApply(contextHints) {
2703
+ this.aiAssistantController?.apply(contextHints ?? undefined).subscribe((state) => {
2385
2704
  this.aiAssistantViewState = state;
2386
2705
  this.syncAiAssistantSession();
2387
2706
  this.cdr.markForCheck();
@@ -2560,7 +2879,7 @@ class ManualFormComponent {
2560
2879
  };
2561
2880
  }
2562
2881
  syncAiAssistantSession(visibility = null) {
2563
- if (!this.enableCustomization())
2882
+ if (!this.showAiAssistant() && !this.enableCustomization())
2564
2883
  return;
2565
2884
  if (!this.aiAssistantOpen && !this.hasAiAssistantSessionState() && visibility !== 'minimized')
2566
2885
  return;
@@ -2602,6 +2921,10 @@ class ManualFormComponent {
2602
2921
  return routePath || 'local';
2603
2922
  }
2604
2923
  resolveAiAssistantSummary() {
2924
+ const retentionPolicy = this.aiAssistantViewState?.runtimeValueProposal?.['retentionPolicy'];
2925
+ if (retentionPolicy === 'zero') {
2926
+ return 'Assistência efêmera de preenchimento (retenção zero).';
2927
+ }
2605
2928
  const status = this.aiAssistantViewState?.statusText?.trim();
2606
2929
  if (status)
2607
2930
  return status;
@@ -2686,6 +3009,7 @@ class ManualFormComponent {
2686
3009
  this.applyInstanceToTemplate(fields);
2687
3010
  this.registerToolbarBindings(fields);
2688
3011
  this.attachMetadataSync();
3012
+ this.ensureRuntimeValueTracking();
2689
3013
  // Auto-save value changes with debounce
2690
3014
  if (this.enableAutoSave() && this.instance) {
2691
3015
  this.instance.form.valueChanges
@@ -3249,11 +3573,477 @@ class ManualFormComponent {
3249
3573
  resetButtonLabel: source.resetButtonLabel ?? base.resetButtonLabel,
3250
3574
  };
3251
3575
  }
3576
+ getRuntimeValueTargetIdentity() {
3577
+ this.syncHostFormGroupReference();
3578
+ this.ensureRuntimeValueTracking();
3579
+ const rawFormId = this.safeAiAssistantFormId() || 'praxis-manual-form';
3580
+ const rawInstanceId = this.componentInstanceId()?.trim() || rawFormId;
3581
+ const rawEntityId = this.entityId();
3582
+ const entityId = typeof rawEntityId === 'number' && Number.isFinite(rawEntityId)
3583
+ ? rawEntityId
3584
+ : typeof rawEntityId === 'string' && rawEntityId.trim().length > 0
3585
+ ? rawEntityId.trim()
3586
+ : null;
3587
+ const resolvedSchemaHash = this.schemaHash()?.trim() ||
3588
+ this.extractGovernedSchemaHash() ||
3589
+ this.instance?.currentConfig?.metadata?.['serverHash']
3590
+ ?.toString()
3591
+ .trim() ||
3592
+ null;
3593
+ const rawMode = this.mode();
3594
+ const normalizedMode = rawMode === 'edit' ? 'edit' : rawMode === 'view' ? 'view' : 'create';
3595
+ return {
3596
+ componentId: rawFormId,
3597
+ instanceId: rawInstanceId,
3598
+ formId: rawFormId,
3599
+ resourcePath: this.resourcePath()?.trim() || null,
3600
+ mode: normalizedMode,
3601
+ entityId,
3602
+ schemaHash: resolvedSchemaHash,
3603
+ valueRevision: this.runtimeValueRevision,
3604
+ };
3605
+ }
3606
+ getRuntimeValueEligibility() {
3607
+ this.syncHostFormGroupReference();
3608
+ this.ensureRuntimeValueTracking();
3609
+ const autoSaveEnabled = Boolean(this.enableAutoSave());
3610
+ const hasPendingAsyncValidators = Boolean(this.formGroup?.pending);
3611
+ const mode = this.getRuntimeValueTargetIdentity().mode;
3612
+ const { writableFields, nonOverwritableFields, hasGovernedSource } = this.collectRuntimeValueFieldClassification();
3613
+ if (mode === 'view') {
3614
+ return {
3615
+ eligible: false,
3616
+ blockReason: 'view-mode-read-only',
3617
+ blockMessage: 'O formulário manual está em modo somente leitura e não aceita preenchimento.',
3618
+ autoSaveEnabled,
3619
+ hasPendingReactiveDeterminations: false,
3620
+ hasPendingAsyncValidators,
3621
+ writableFields: [],
3622
+ nonOverwritableFields,
3623
+ };
3624
+ }
3625
+ if (autoSaveEnabled) {
3626
+ return {
3627
+ eligible: false,
3628
+ blockReason: 'auto-save-enabled',
3629
+ blockMessage: 'A aplicação automática está bloqueada porque o salvamento automático (enableAutoSave) está ativo neste formulário.',
3630
+ autoSaveEnabled: true,
3631
+ hasPendingReactiveDeterminations: false,
3632
+ hasPendingAsyncValidators,
3633
+ writableFields,
3634
+ nonOverwritableFields,
3635
+ };
3636
+ }
3637
+ if (!hasGovernedSource) {
3638
+ return {
3639
+ eligible: false,
3640
+ blockReason: 'governed-schema-required',
3641
+ blockMessage: 'O formulário manual exige contrato de criação ou artefato governado (resourcePath/governedSchema) para validar campos elegíveis; allowedFields apenas do navegador não autoriza escrita.',
3642
+ autoSaveEnabled: false,
3643
+ hasPendingReactiveDeterminations: false,
3644
+ hasPendingAsyncValidators,
3645
+ writableFields: [],
3646
+ nonOverwritableFields,
3647
+ };
3648
+ }
3649
+ if (hasPendingAsyncValidators) {
3650
+ return {
3651
+ eligible: false,
3652
+ blockReason: 'pending-async-validators',
3653
+ blockMessage: 'Existem validações assíncronas pendentes no formulário. Aguarde a conclusão antes de aplicar valores.',
3654
+ autoSaveEnabled: false,
3655
+ hasPendingReactiveDeterminations: false,
3656
+ hasPendingAsyncValidators: true,
3657
+ writableFields,
3658
+ nonOverwritableFields,
3659
+ };
3660
+ }
3661
+ if (writableFields.length === 0) {
3662
+ return {
3663
+ eligible: false,
3664
+ blockReason: 'no-writable-fields',
3665
+ blockMessage: 'O formulário manual não possui campos elegíveis para preenchimento assistido.',
3666
+ autoSaveEnabled: false,
3667
+ hasPendingReactiveDeterminations: false,
3668
+ hasPendingAsyncValidators,
3669
+ writableFields,
3670
+ nonOverwritableFields,
3671
+ };
3672
+ }
3673
+ return {
3674
+ eligible: true,
3675
+ blockReason: null,
3676
+ blockMessage: null,
3677
+ autoSaveEnabled: false,
3678
+ hasPendingReactiveDeterminations: false,
3679
+ hasPendingAsyncValidators,
3680
+ writableFields,
3681
+ nonOverwritableFields,
3682
+ };
3683
+ }
3684
+ previewRuntimeValues(proposal, options) {
3685
+ this.syncHostFormGroupReference();
3686
+ this.ensureRuntimeValueTracking();
3687
+ return previewRuntimeFormValueProposal(this.createRuntimeFormHostCallbacks(), proposal, options);
3688
+ }
3689
+ applyRuntimeValues(request) {
3690
+ this.syncHostFormGroupReference();
3691
+ this.ensureRuntimeValueTracking();
3692
+ const receipt = applyRuntimeFormValueProposal(this.createRuntimeFormHostCallbacks(), this.runtimeValueJournal, request);
3693
+ if (receipt.appliedFields.length > 0) {
3694
+ this.cdr.markForCheck();
3695
+ }
3696
+ return receipt;
3697
+ }
3698
+ undoRuntimeValues(receiptId) {
3699
+ this.syncHostFormGroupReference();
3700
+ this.ensureRuntimeValueTracking();
3701
+ const receipt = undoRuntimeFormValueApply(this.createRuntimeFormHostCallbacks(), this.runtimeValueJournal, receiptId);
3702
+ if (receipt.revertedFields.length > 0) {
3703
+ this.cdr.markForCheck();
3704
+ }
3705
+ return receipt;
3706
+ }
3707
+ clearRuntimeValueControlSubscriptions() {
3708
+ this.runtimeValueStatusSub?.unsubscribe();
3709
+ this.runtimeValueStatusSub = undefined;
3710
+ for (const entry of this.runtimeValueTrackedControls.values()) {
3711
+ entry.sub.unsubscribe();
3712
+ }
3713
+ this.runtimeValueTrackedControls.clear();
3714
+ this.runtimeValueTrackedForm = null;
3715
+ }
3716
+ collectLeafFormControls(group, prefix = '', out = new Map()) {
3717
+ if (!group?.controls) {
3718
+ return out;
3719
+ }
3720
+ for (const [key, control] of Object.entries(group.controls)) {
3721
+ const path = prefix ? `${prefix}.${key}` : key;
3722
+ if (control instanceof FormGroup) {
3723
+ this.collectLeafFormControls(control, path, out);
3724
+ }
3725
+ else if (control) {
3726
+ out.set(path, control);
3727
+ }
3728
+ }
3729
+ return out;
3730
+ }
3731
+ ensureRuntimeValueTracking() {
3732
+ if (!this.formGroup) {
3733
+ return;
3734
+ }
3735
+ if (this.runtimeValueTrackedForm !== this.formGroup) {
3736
+ this.clearRuntimeValueControlSubscriptions();
3737
+ this.runtimeValueTrackedForm = this.formGroup;
3738
+ this.runtimeValueStatusSub = this.formGroup.statusChanges
3739
+ .pipe(takeUntilDestroyed(this.destroyRef))
3740
+ .subscribe(() => {
3741
+ this.cdr.markForCheck();
3742
+ });
3743
+ }
3744
+ const leafControls = this.collectLeafFormControls(this.formGroup);
3745
+ for (const [fieldPath, control] of leafControls.entries()) {
3746
+ const existing = this.runtimeValueTrackedControls.get(fieldPath);
3747
+ if (existing?.control === control) {
3748
+ continue;
3749
+ }
3750
+ existing?.sub.unsubscribe();
3751
+ const sub = control.valueChanges
3752
+ .pipe(takeUntilDestroyed(this.destroyRef))
3753
+ .subscribe(() => {
3754
+ if (this.suppressRuntimeValueTrackingDepth > 0) {
3755
+ return;
3756
+ }
3757
+ this.runtimeValueRevision += 1;
3758
+ const instanceKey = instanceKeyFor(this.getRuntimeValueTargetIdentity());
3759
+ this.runtimeValueJournal.markFieldManuallyEdited(instanceKey, fieldPath);
3760
+ });
3761
+ this.runtimeValueTrackedControls.set(fieldPath, { control, sub });
3762
+ }
3763
+ }
3764
+ createRuntimeFormHostCallbacks() {
3765
+ return {
3766
+ getTargetIdentity: () => this.getRuntimeValueTargetIdentity(),
3767
+ getEligibility: () => this.getRuntimeValueEligibility(),
3768
+ getControl: (fieldPath) => {
3769
+ const control = this.formGroup?.get(fieldPath) ?? null;
3770
+ if (!control) {
3771
+ return null;
3772
+ }
3773
+ return {
3774
+ exists: true,
3775
+ getValue: () => control.value,
3776
+ setValue: (value) => {
3777
+ control.setValue(value);
3778
+ },
3779
+ isDirty: () => control.dirty,
3780
+ setDirty: (dirty) => {
3781
+ if (dirty) {
3782
+ control.markAsDirty();
3783
+ }
3784
+ else {
3785
+ control.markAsPristine({ onlySelf: true });
3786
+ const anyControlDirty = Object.values(this.formGroup?.controls ?? {}).some((item) => item.dirty);
3787
+ if (!anyControlDirty) {
3788
+ this.formGroup?.markAsPristine({ onlySelf: true });
3789
+ }
3790
+ }
3791
+ },
3792
+ isTouched: () => control.touched,
3793
+ setTouched: (touched) => {
3794
+ if (touched) {
3795
+ control.markAsTouched();
3796
+ }
3797
+ else {
3798
+ control.markAsUntouched({ onlySelf: true });
3799
+ const anyControlTouched = Object.values(this.formGroup?.controls ?? {}).some((item) => item.touched);
3800
+ if (!anyControlTouched) {
3801
+ this.formGroup?.markAsUntouched({ onlySelf: true });
3802
+ }
3803
+ }
3804
+ },
3805
+ };
3806
+ },
3807
+ incrementValueRevision: () => {
3808
+ this.runtimeValueRevision += 1;
3809
+ return this.runtimeValueRevision;
3810
+ },
3811
+ withSuppressedCommandSideEffects: (fn) => {
3812
+ this.suppressRuntimeValueTrackingDepth += 1;
3813
+ try {
3814
+ return fn();
3815
+ }
3816
+ finally {
3817
+ this.suppressRuntimeValueTrackingDepth = Math.max(0, this.suppressRuntimeValueTrackingDepth - 1);
3818
+ }
3819
+ },
3820
+ };
3821
+ }
3822
+ extractGovernedSchemaHash() {
3823
+ const governed = this.governedSchema();
3824
+ if (!governed || Array.isArray(governed) || typeof governed !== 'object') {
3825
+ return null;
3826
+ }
3827
+ const rawHash = governed['schemaHash'] ??
3828
+ governed['x-schema-hash'];
3829
+ return typeof rawHash === 'string' && rawHash.trim().length > 0
3830
+ ? rawHash.trim()
3831
+ : null;
3832
+ }
3833
+ extractGovernedFieldMap() {
3834
+ const governed = this.governedSchema();
3835
+ const fieldsByName = new Map();
3836
+ if (Array.isArray(governed)) {
3837
+ for (const item of governed) {
3838
+ if (item && typeof item === 'object' && typeof item.name === 'string') {
3839
+ fieldsByName.set(item.name, item);
3840
+ }
3841
+ }
3842
+ return {
3843
+ hasGovernedSource: true,
3844
+ strictGovernedAllowlist: true,
3845
+ fieldsByName,
3846
+ };
3847
+ }
3848
+ if (governed && typeof governed === 'object') {
3849
+ const properties = governed['properties'];
3850
+ const requiredSet = new Set(Array.isArray(governed['required'])
3851
+ ? governed['required']
3852
+ : []);
3853
+ if (properties && typeof properties === 'object' && !Array.isArray(properties)) {
3854
+ for (const [fieldName, prop] of Object.entries(properties)) {
3855
+ if (prop && typeof prop === 'object') {
3856
+ fieldsByName.set(fieldName, {
3857
+ ...prop,
3858
+ name: fieldName,
3859
+ required: prop['required'] ?? requiredSet.has(fieldName),
3860
+ });
3861
+ }
3862
+ }
3863
+ }
3864
+ return {
3865
+ hasGovernedSource: true,
3866
+ strictGovernedAllowlist: true,
3867
+ fieldsByName,
3868
+ };
3869
+ }
3870
+ const hasResourceOrHash = Boolean(this.resourcePath()?.trim() || this.schemaHash()?.trim());
3871
+ if (hasResourceOrHash) {
3872
+ for (const meta of this.instance?.currentConfig?.fieldMetadata ?? []) {
3873
+ if (meta?.name) {
3874
+ fieldsByName.set(meta.name, meta);
3875
+ }
3876
+ }
3877
+ return {
3878
+ hasGovernedSource: true,
3879
+ strictGovernedAllowlist: fieldsByName.size > 0,
3880
+ fieldsByName,
3881
+ };
3882
+ }
3883
+ return {
3884
+ hasGovernedSource: false,
3885
+ strictGovernedAllowlist: false,
3886
+ fieldsByName,
3887
+ };
3888
+ }
3889
+ collectRuntimeValueFieldClassification() {
3890
+ const writableFields = [];
3891
+ const nonOverwritableFields = [];
3892
+ const { hasGovernedSource, strictGovernedAllowlist, fieldsByName } = this.extractGovernedFieldMap();
3893
+ const instanceMetaByName = new Map();
3894
+ for (const meta of this.instance?.currentConfig?.fieldMetadata ?? []) {
3895
+ if (meta?.name) {
3896
+ instanceMetaByName.set(meta.name, meta);
3897
+ }
3898
+ }
3899
+ const leafControls = this.collectLeafFormControls(this.formGroup);
3900
+ const allFieldNames = new Set([
3901
+ ...fieldsByName.keys(),
3902
+ ...instanceMetaByName.keys(),
3903
+ ...leafControls.keys(),
3904
+ ]);
3905
+ const evalMode = this.mode() === 'edit' ? 'edit' : this.mode() === 'view' ? 'view' : 'create';
3906
+ for (const fieldPath of allFieldNames) {
3907
+ const governedField = fieldsByName.get(fieldPath);
3908
+ const instanceField = instanceMetaByName.get(fieldPath);
3909
+ const field = {
3910
+ ...(instanceField ?? {}),
3911
+ ...(governedField ?? {}),
3912
+ };
3913
+ const control = this.formGroup?.get(fieldPath) ?? null;
3914
+ const label = typeof field['label'] === 'string' && field['label'].trim()
3915
+ ? field['label'].trim()
3916
+ : typeof field['x-ui']?.['label'] === 'string' &&
3917
+ field['x-ui']['label'].trim()
3918
+ ? field['x-ui']['label'].trim()
3919
+ : fieldPath;
3920
+ if (strictGovernedAllowlist && !fieldsByName.has(fieldPath)) {
3921
+ nonOverwritableFields.push({
3922
+ fieldPath,
3923
+ label,
3924
+ reason: 'restricted-by-field-access',
3925
+ message: 'Campo ausente no contrato de criação / artefato governado do formulário manual.',
3926
+ });
3927
+ continue;
3928
+ }
3929
+ const xUi = (field['x-ui'] ?? {});
3930
+ const rawFieldAccess = field['fieldAccess'] ?? xUi['fieldAccess'];
3931
+ const access = evaluateFieldAccess(rawFieldAccess);
3932
+ const rawAiPolicy = String(field['aiUsagePolicy'] ??
3933
+ field['domainGovernance']?.['aiUsagePolicy'] ??
3934
+ xUi['aiUsagePolicy'] ??
3935
+ xUi['domainGovernance']?.['aiUsagePolicy'] ??
3936
+ rawFieldAccess?.['aiUsagePolicy'] ??
3937
+ '')
3938
+ .trim()
3939
+ .toUpperCase();
3940
+ const aiDisallowed = field['allowedForAiPrompting'] === false ||
3941
+ field['domainGovernance']?.['allowedForAiPrompting'] === false ||
3942
+ xUi['allowedForAiPrompting'] === false ||
3943
+ rawFieldAccess?.['allowedForAiPrompting'] === false ||
3944
+ rawAiPolicy === 'NEVER' ||
3945
+ rawAiPolicy === 'NONE' ||
3946
+ rawAiPolicy === 'FORBIDDEN' ||
3947
+ rawAiPolicy === 'READ_ONLY' ||
3948
+ rawAiPolicy === 'MASKED_ONLY' ||
3949
+ rawAiPolicy === 'REDACTED_ONLY';
3950
+ if (aiDisallowed) {
3951
+ nonOverwritableFields.push({
3952
+ fieldPath,
3953
+ label,
3954
+ reason: 'restricted-by-ai-policy',
3955
+ message: 'Campo restrito pela governança de IA (@DomainGovernance / AiUsagePolicy).',
3956
+ });
3957
+ continue;
3958
+ }
3959
+ const restrictedByFieldAccess = rawFieldAccess != null &&
3960
+ (access.editable === false ||
3961
+ access.visible === false ||
3962
+ (rawFieldAccess['creatable'] === false && evalMode === 'create') ||
3963
+ (rawFieldAccess['updatable'] === false && evalMode === 'edit') ||
3964
+ rawFieldAccess['writable'] === false);
3965
+ if (restrictedByFieldAccess) {
3966
+ nonOverwritableFields.push({
3967
+ fieldPath,
3968
+ label,
3969
+ reason: 'restricted-by-field-access',
3970
+ message: 'Campo restrito pela política de acesso (x-ui.fieldAccess).',
3971
+ });
3972
+ continue;
3973
+ }
3974
+ const isReadOnly = evalMode === 'view' ||
3975
+ field['readOnly'] === true ||
3976
+ field['readonly'] === true ||
3977
+ xUi['readOnly'] === true ||
3978
+ xUi['readonly'] === true;
3979
+ if (isReadOnly) {
3980
+ nonOverwritableFields.push({
3981
+ fieldPath,
3982
+ label,
3983
+ reason: 'read-only',
3984
+ message: 'Campo somente leitura não pode ser sobrescrito.',
3985
+ });
3986
+ continue;
3987
+ }
3988
+ const isDisabled = Boolean(control?.disabled) ||
3989
+ field['disabled'] === true ||
3990
+ xUi['disabled'] === true;
3991
+ if (isDisabled) {
3992
+ nonOverwritableFields.push({
3993
+ fieldPath,
3994
+ label,
3995
+ reason: 'disabled',
3996
+ message: 'Campo desabilitado não pode ser sobrescrito.',
3997
+ });
3998
+ continue;
3999
+ }
4000
+ const isHidden = field['hidden'] === true ||
4001
+ field['formHidden'] === true ||
4002
+ field['visible'] === false ||
4003
+ xUi['hidden'] === true ||
4004
+ xUi['visible'] === false;
4005
+ if (isHidden) {
4006
+ nonOverwritableFields.push({
4007
+ fieldPath,
4008
+ label,
4009
+ reason: 'hidden',
4010
+ message: 'Campo oculto não pode ser sobrescrito.',
4011
+ });
4012
+ continue;
4013
+ }
4014
+ if (!control) {
4015
+ nonOverwritableFields.push({
4016
+ fieldPath,
4017
+ label,
4018
+ reason: 'unsupported-control',
4019
+ message: 'Controle não encontrado no FormGroup do formulário manual.',
4020
+ });
4021
+ continue;
4022
+ }
4023
+ const optionSource = (field['optionSource'] ??
4024
+ xUi['optionSource'] ??
4025
+ null);
4026
+ writableFields.push({
4027
+ fieldPath,
4028
+ label,
4029
+ dataType: field['type'] ??
4030
+ field['dataType'] ??
4031
+ null,
4032
+ controlType: field['controlType'] ??
4033
+ xUi['controlType'] ??
4034
+ null,
4035
+ required: Boolean(field['required'] || field['validators']?.['required']),
4036
+ optionSourceKey: typeof optionSource?.['key'] === 'string' ? optionSource['key'] : null,
4037
+ optionSourceType: typeof optionSource?.['type'] === 'string' ? optionSource['type'] : null,
4038
+ });
4039
+ }
4040
+ return { writableFields, nonOverwritableFields, hasGovernedSource };
4041
+ }
3252
4042
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: ManualFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3253
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: ManualFormComponent, isStandalone: true, selector: "praxis-manual-form", inputs: { formId: { classPropertyName: "formId", publicName: "formId", isSignal: true, isRequired: true, transformFunction: null }, formTitle: { classPropertyName: "formTitle", publicName: "formTitle", isSignal: true, isRequired: false, transformFunction: null }, formDescription: { classPropertyName: "formDescription", publicName: "formDescription", isSignal: true, isRequired: false, transformFunction: null }, actions: { classPropertyName: "actions", publicName: "actions", isSignal: true, isRequired: false, transformFunction: null }, showHeader: { classPropertyName: "showHeader", publicName: "showHeader", isSignal: true, isRequired: false, transformFunction: null }, showActions: { classPropertyName: "showActions", publicName: "showActions", isSignal: true, isRequired: false, transformFunction: null }, enableAutoSave: { classPropertyName: "enableAutoSave", publicName: "enableAutoSave", isSignal: true, isRequired: false, transformFunction: null }, componentInstanceId: { classPropertyName: "componentInstanceId", publicName: "componentInstanceId", isSignal: true, isRequired: false, transformFunction: null }, enableCustomization: { classPropertyName: "enableCustomization", publicName: "enableCustomization", isSignal: true, isRequired: false, transformFunction: null }, persistenceOptions: { classPropertyName: "persistenceOptions", publicName: "persistenceOptions", isSignal: true, isRequired: false, transformFunction: null }, usePathNames: { classPropertyName: "usePathNames", publicName: "usePathNames", isSignal: true, isRequired: false, transformFunction: null }, autoSaveDebounceMs: { classPropertyName: "autoSaveDebounceMs", publicName: "autoSaveDebounceMs", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { submitted: "submitted", saved: "saved", resetEvent: "reset", metadataChange: "metadataChange" }, providers: [
4043
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: ManualFormComponent, isStandalone: true, selector: "praxis-manual-form", inputs: { formId: { classPropertyName: "formId", publicName: "formId", isSignal: true, isRequired: true, transformFunction: null }, formTitle: { classPropertyName: "formTitle", publicName: "formTitle", isSignal: true, isRequired: false, transformFunction: null }, formDescription: { classPropertyName: "formDescription", publicName: "formDescription", isSignal: true, isRequired: false, transformFunction: null }, actions: { classPropertyName: "actions", publicName: "actions", isSignal: true, isRequired: false, transformFunction: null }, showHeader: { classPropertyName: "showHeader", publicName: "showHeader", isSignal: true, isRequired: false, transformFunction: null }, showActions: { classPropertyName: "showActions", publicName: "showActions", isSignal: true, isRequired: false, transformFunction: null }, enableAutoSave: { classPropertyName: "enableAutoSave", publicName: "enableAutoSave", isSignal: true, isRequired: false, transformFunction: null }, componentInstanceId: { classPropertyName: "componentInstanceId", publicName: "componentInstanceId", isSignal: true, isRequired: false, transformFunction: null }, showAiAssistant: { classPropertyName: "showAiAssistant", publicName: "showAiAssistant", isSignal: true, isRequired: false, transformFunction: null }, enableCustomization: { classPropertyName: "enableCustomization", publicName: "enableCustomization", isSignal: true, isRequired: false, transformFunction: null }, persistenceOptions: { classPropertyName: "persistenceOptions", publicName: "persistenceOptions", isSignal: true, isRequired: false, transformFunction: null }, usePathNames: { classPropertyName: "usePathNames", publicName: "usePathNames", isSignal: true, isRequired: false, transformFunction: null }, autoSaveDebounceMs: { classPropertyName: "autoSaveDebounceMs", publicName: "autoSaveDebounceMs", isSignal: true, isRequired: false, transformFunction: null }, resourcePath: { classPropertyName: "resourcePath", publicName: "resourcePath", isSignal: true, isRequired: false, transformFunction: null }, governedSchema: { classPropertyName: "governedSchema", publicName: "governedSchema", isSignal: true, isRequired: false, transformFunction: null }, schemaHash: { classPropertyName: "schemaHash", publicName: "schemaHash", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, entityId: { classPropertyName: "entityId", publicName: "entityId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { submitted: "submitted", saved: "saved", resetEvent: "reset", metadataChange: "metadataChange" }, providers: [
3254
4044
  // Provide a ControlContainer at the host boundary so projected formControlName can resolve it
3255
4045
  { provide: ControlContainer, useExisting: ManualFormComponent },
3256
- ], queries: [{ propertyName: "formControls", predicate: FormControlName, descendants: true }], ngImport: i0, template: "<div class=\"pdx-manual-form\">\n @if (showHeader()) {\n <praxis-manual-form-header [instance]=\"instance\" [title]=\"formTitle()\" [description]=\"formDescription()\"\n [enableCustomization]=\"enableCustomization()\" (editForm)=\"openFormEditor()\" (save)=\"handleSave()\"\n (reset)=\"handleReset()\"></praxis-manual-form-header>\n }\n\n @if (enableCustomization()) {\n <div class=\"pdx-manual-form__assistant\">\n <button\n type=\"button\"\n class=\"pdx-manual-form__assistant-trigger\"\n (click)=\"openAiAssistant()\"\n aria-label=\"Abrir copiloto semantico Praxis do formulario manual\"\n data-testid=\"praxis-manual-form-ai-assistant-trigger\"\n >\n Copiloto Praxis\n </button>\n </div>\n }\n\n @if (aiAssistantOpen && aiAssistantViewState) {\n <praxis-ai-assistant-shell\n [labels]=\"aiAssistantLabels\"\n [mode]=\"aiAssistantViewState.mode\"\n [state]=\"aiAssistantViewState.state\"\n [contextItems]=\"aiAssistantViewState.contextItems\"\n [attachments]=\"aiAssistantViewState.attachments\"\n [messages]=\"aiAssistantViewState.messages\"\n [quickReplies]=\"aiAssistantViewState.quickReplies\"\n [prompt]=\"aiAssistantPrompt\"\n [statusText]=\"aiAssistantViewState.statusText\"\n [errorText]=\"aiAssistantViewState.errorText\"\n [busy]=\"aiAssistantViewState.state === 'processing' || aiAssistantViewState.state === 'applying'\"\n [canApply]=\"aiAssistantViewState.canApply\"\n [layout]=\"aiAssistantLayout\"\n testIdPrefix=\"praxis-manual-form-ai-assistant\"\n (promptChange)=\"onAiAssistantPromptChange($event)\"\n (submitPrompt)=\"onAiAssistantSubmit($event)\"\n (apply)=\"onAiAssistantApply()\"\n (retryTurn)=\"onAiAssistantRetry()\"\n (cancelTurn)=\"onAiAssistantCancel()\"\n (close)=\"closeAiAssistant()\"\n (quickReply)=\"onAiAssistantQuickReply($event)\"\n (editMessage)=\"onAiAssistantEditMessage($event)\"\n (resendMessage)=\"onAiAssistantResendMessage($event)\"\n (layoutChange)=\"onAiAssistantLayoutChange($event)\"\n ></praxis-ai-assistant-shell>\n }\n\n <form class=\"pdx-manual-form__form\" [formGroup]=\"formGroup\" (submit)=\"handleSubmit(); $event.preventDefault()\">\n <ng-content></ng-content>\n </form>\n\n @if (showActions() && resolvedActions) {\n <praxis-manual-form-actions [actions]=\"resolvedActions\"\n (actionClick)=\"handleAction($event)\"></praxis-manual-form-actions>\n }\n</div>\n", styles: [".pdx-manual-form{display:flex;flex-direction:column;gap:var(--pdx-manual-form-gap, 24px);color:var(--md-sys-color-on-surface)}.pdx-manual-form__form{display:grid;gap:var(--pdx-manual-form-field-gap, 16px);padding:var(--pdx-manual-form-padding, 20px);border-radius:var(--pdx-manual-form-radius, 16px);background:var(--pdx-manual-form-surface, var(--md-sys-color-surface-container));border:1px solid var(--pdx-manual-form-outline, var(--md-sys-color-outline-variant));box-shadow:var(--pdx-manual-form-shadow, var(--md-sys-elevation-level1, none))}.pdx-manual-form__form:focus-within{border-color:var(--pdx-manual-form-focus, var(--md-sys-color-primary));box-shadow:0 0 0 2px var(--md-sys-color-primary),var(--pdx-manual-form-shadow, var(--md-sys-elevation-level1, none))}.pdx-manual-form__assistant{display:flex;justify-content:flex-end}.pdx-manual-form__assistant-trigger{border:0;border-radius:999px;padding:8px 14px;cursor:pointer;color:var(--md-sys-color-on-primary, #fff);background:var(--md-sys-color-primary, #3451d1);box-shadow:var(--md-sys-elevation-level2, 0 4px 12px rgba(0, 0, 0, .18))}.pdx-manual-form__assistant-trigger:hover{background:var(--md-sys-color-primary-container, #223fb6)}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: PraxisAiAssistantShellComponent, selector: "praxis-ai-assistant-shell", inputs: ["labels", "mode", "state", "contextItems", "attachments", "messages", "quickReplies", "recommendedIntents", "prompt", "statusText", "errorText", "testIdPrefix", "panelTestId", "submitTestId", "applyTestId", "primaryAction", "secondaryActions", "governanceActions", "busy", "canSubmit", "canApply", "submitOnEnter", "showAttachAction", "enablePastedAttachments", "enableFileAttachments", "attachmentAccept", "attachmentMultiple", "voiceInputMode", "voiceLanguage", "draggable", "resizable", "minWidth", "minHeight", "margin", "layout"], outputs: ["promptChange", "submitPrompt", "apply", "retryTurn", "cancelTurn", "shellAction", "close", "attach", "attachmentsPasted", "attachmentsSelected", "removeAttachment", "messageAction", "editMessage", "resendMessage", "quickReply", "recommendedIntent", "layoutChange"] }, { kind: "component", type: ManualFormHeaderComponent, selector: "praxis-manual-form-header", inputs: ["instance", "title", "description", "saveLabel", "resetLabel", "enableCustomization", "editFormLabel"], outputs: ["save", "reset", "editForm"] }, { kind: "component", type: ManualFormActionsComponent, selector: "praxis-manual-form-actions", inputs: ["actions", "trackByFn"], outputs: ["actionClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4046
+ ], queries: [{ propertyName: "formControls", predicate: FormControlName, descendants: true }], ngImport: i0, template: "<div class=\"pdx-manual-form\">\n @if (showHeader()) {\n <praxis-manual-form-header [instance]=\"instance\" [title]=\"formTitle()\" [description]=\"formDescription()\"\n [enableCustomization]=\"enableCustomization()\" (editForm)=\"openFormEditor()\" (save)=\"handleSave()\"\n (reset)=\"handleReset()\"></praxis-manual-form-header>\n }\n\n @if (showAiAssistant() || enableCustomization()) {\n <div class=\"pdx-manual-form__assistant\">\n <button\n type=\"button\"\n class=\"pdx-manual-form__assistant-trigger\"\n (click)=\"openAiAssistant()\"\n [attr.aria-label]=\"enableCustomization() ? 'Abrir copiloto sem\u00E2ntico Praxis do formul\u00E1rio manual' : 'Abrir assistente de preenchimento do formul\u00E1rio manual'\"\n data-testid=\"praxis-manual-form-ai-assistant-trigger\"\n >\n {{ enableCustomization() ? 'Copiloto Praxis' : 'Assistente de preenchimento' }}\n </button>\n </div>\n }\n\n @if (aiAssistantOpen && aiAssistantViewState) {\n <praxis-ai-assistant-shell\n [labels]=\"aiAssistantLabels\"\n [mode]=\"aiAssistantViewState.mode\"\n [state]=\"aiAssistantViewState.state\"\n [contextItems]=\"aiAssistantViewState.contextItems\"\n [attachments]=\"aiAssistantViewState.attachments\"\n [messages]=\"aiAssistantViewState.messages\"\n [quickReplies]=\"aiAssistantViewState.quickReplies\"\n [prompt]=\"aiAssistantPrompt\"\n [statusText]=\"aiAssistantViewState.statusText\"\n [errorText]=\"aiAssistantViewState.errorText\"\n [busy]=\"aiAssistantViewState.state === 'processing' || aiAssistantViewState.state === 'applying'\"\n [canApply]=\"aiAssistantViewState.canApply\"\n [preview]=\"aiAssistantViewState.preview\"\n [layout]=\"aiAssistantLayout\"\n testIdPrefix=\"praxis-manual-form-ai-assistant\"\n (promptChange)=\"onAiAssistantPromptChange($event)\"\n (submitPrompt)=\"onAiAssistantSubmit($event)\"\n (apply)=\"onAiAssistantApply($event)\"\n (retryTurn)=\"onAiAssistantRetry()\"\n (cancelTurn)=\"onAiAssistantCancel()\"\n (close)=\"closeAiAssistant()\"\n (quickReply)=\"onAiAssistantQuickReply($event)\"\n (editMessage)=\"onAiAssistantEditMessage($event)\"\n (resendMessage)=\"onAiAssistantResendMessage($event)\"\n (layoutChange)=\"onAiAssistantLayoutChange($event)\"\n ></praxis-ai-assistant-shell>\n }\n\n <form class=\"pdx-manual-form__form\" [formGroup]=\"formGroup\" (submit)=\"handleSubmit(); $event.preventDefault()\">\n <ng-content></ng-content>\n </form>\n\n @if (showActions() && resolvedActions) {\n <praxis-manual-form-actions [actions]=\"resolvedActions\" [submitDisabled]=\"!effectiveFormIsValid\"\n (actionClick)=\"handleAction($event)\"></praxis-manual-form-actions>\n }\n</div>\n", styles: [".pdx-manual-form{display:flex;flex-direction:column;gap:var(--pdx-manual-form-gap, 24px);color:var(--md-sys-color-on-surface)}.pdx-manual-form__form{display:grid;gap:var(--pdx-manual-form-field-gap, 16px);padding:var(--pdx-manual-form-padding, 20px);border-radius:var(--pdx-manual-form-radius, 16px);background:var(--pdx-manual-form-surface, var(--md-sys-color-surface-container));border:1px solid var(--pdx-manual-form-outline, var(--md-sys-color-outline-variant));box-shadow:var(--pdx-manual-form-shadow, var(--md-sys-elevation-level1, none))}.pdx-manual-form__form:focus-within{border-color:var(--pdx-manual-form-focus, var(--md-sys-color-primary));box-shadow:0 0 0 2px var(--md-sys-color-primary),var(--pdx-manual-form-shadow, var(--md-sys-elevation-level1, none))}.pdx-manual-form__assistant{display:flex;justify-content:flex-end}.pdx-manual-form__assistant-trigger{border:0;border-radius:999px;padding:8px 14px;cursor:pointer;color:var(--md-sys-color-on-primary, #fff);background:var(--md-sys-color-primary, #3451d1);box-shadow:var(--md-sys-elevation-level2, 0 4px 12px rgba(0, 0, 0, .18))}.pdx-manual-form__assistant-trigger:hover{background:var(--md-sys-color-primary-container, #223fb6)}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: PraxisAiAssistantShellComponent, selector: "praxis-ai-assistant-shell", inputs: ["labels", "mode", "state", "contextItems", "attachments", "messages", "quickReplies", "recommendedIntents", "prompt", "statusText", "errorText", "testIdPrefix", "panelTestId", "submitTestId", "applyTestId", "primaryAction", "secondaryActions", "governanceActions", "busy", "canSubmit", "canApply", "preview", "submitOnEnter", "showAttachAction", "enablePastedAttachments", "enableFileAttachments", "attachmentAccept", "attachmentMultiple", "voiceInputMode", "voiceLanguage", "draggable", "resizable", "minWidth", "minHeight", "margin", "layout"], outputs: ["promptChange", "submitPrompt", "apply", "retryTurn", "cancelTurn", "shellAction", "close", "attach", "attachmentsPasted", "attachmentsSelected", "removeAttachment", "messageAction", "editMessage", "resendMessage", "quickReply", "recommendedIntent", "layoutChange"] }, { kind: "component", type: ManualFormHeaderComponent, selector: "praxis-manual-form-header", inputs: ["instance", "title", "description", "saveLabel", "resetLabel", "enableCustomization", "editFormLabel"], outputs: ["save", "reset", "editForm"] }, { kind: "component", type: ManualFormActionsComponent, selector: "praxis-manual-form-actions", inputs: ["actions", "submitDisabled", "trackByFn"], outputs: ["actionClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3257
4047
  }
3258
4048
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: ManualFormComponent, decorators: [{
3259
4049
  type: Component,
@@ -3265,8 +4055,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
3265
4055
  ], providers: [
3266
4056
  // Provide a ControlContainer at the host boundary so projected formControlName can resolve it
3267
4057
  { provide: ControlContainer, useExisting: ManualFormComponent },
3268
- ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"pdx-manual-form\">\n @if (showHeader()) {\n <praxis-manual-form-header [instance]=\"instance\" [title]=\"formTitle()\" [description]=\"formDescription()\"\n [enableCustomization]=\"enableCustomization()\" (editForm)=\"openFormEditor()\" (save)=\"handleSave()\"\n (reset)=\"handleReset()\"></praxis-manual-form-header>\n }\n\n @if (enableCustomization()) {\n <div class=\"pdx-manual-form__assistant\">\n <button\n type=\"button\"\n class=\"pdx-manual-form__assistant-trigger\"\n (click)=\"openAiAssistant()\"\n aria-label=\"Abrir copiloto semantico Praxis do formulario manual\"\n data-testid=\"praxis-manual-form-ai-assistant-trigger\"\n >\n Copiloto Praxis\n </button>\n </div>\n }\n\n @if (aiAssistantOpen && aiAssistantViewState) {\n <praxis-ai-assistant-shell\n [labels]=\"aiAssistantLabels\"\n [mode]=\"aiAssistantViewState.mode\"\n [state]=\"aiAssistantViewState.state\"\n [contextItems]=\"aiAssistantViewState.contextItems\"\n [attachments]=\"aiAssistantViewState.attachments\"\n [messages]=\"aiAssistantViewState.messages\"\n [quickReplies]=\"aiAssistantViewState.quickReplies\"\n [prompt]=\"aiAssistantPrompt\"\n [statusText]=\"aiAssistantViewState.statusText\"\n [errorText]=\"aiAssistantViewState.errorText\"\n [busy]=\"aiAssistantViewState.state === 'processing' || aiAssistantViewState.state === 'applying'\"\n [canApply]=\"aiAssistantViewState.canApply\"\n [layout]=\"aiAssistantLayout\"\n testIdPrefix=\"praxis-manual-form-ai-assistant\"\n (promptChange)=\"onAiAssistantPromptChange($event)\"\n (submitPrompt)=\"onAiAssistantSubmit($event)\"\n (apply)=\"onAiAssistantApply()\"\n (retryTurn)=\"onAiAssistantRetry()\"\n (cancelTurn)=\"onAiAssistantCancel()\"\n (close)=\"closeAiAssistant()\"\n (quickReply)=\"onAiAssistantQuickReply($event)\"\n (editMessage)=\"onAiAssistantEditMessage($event)\"\n (resendMessage)=\"onAiAssistantResendMessage($event)\"\n (layoutChange)=\"onAiAssistantLayoutChange($event)\"\n ></praxis-ai-assistant-shell>\n }\n\n <form class=\"pdx-manual-form__form\" [formGroup]=\"formGroup\" (submit)=\"handleSubmit(); $event.preventDefault()\">\n <ng-content></ng-content>\n </form>\n\n @if (showActions() && resolvedActions) {\n <praxis-manual-form-actions [actions]=\"resolvedActions\"\n (actionClick)=\"handleAction($event)\"></praxis-manual-form-actions>\n }\n</div>\n", styles: [".pdx-manual-form{display:flex;flex-direction:column;gap:var(--pdx-manual-form-gap, 24px);color:var(--md-sys-color-on-surface)}.pdx-manual-form__form{display:grid;gap:var(--pdx-manual-form-field-gap, 16px);padding:var(--pdx-manual-form-padding, 20px);border-radius:var(--pdx-manual-form-radius, 16px);background:var(--pdx-manual-form-surface, var(--md-sys-color-surface-container));border:1px solid var(--pdx-manual-form-outline, var(--md-sys-color-outline-variant));box-shadow:var(--pdx-manual-form-shadow, var(--md-sys-elevation-level1, none))}.pdx-manual-form__form:focus-within{border-color:var(--pdx-manual-form-focus, var(--md-sys-color-primary));box-shadow:0 0 0 2px var(--md-sys-color-primary),var(--pdx-manual-form-shadow, var(--md-sys-elevation-level1, none))}.pdx-manual-form__assistant{display:flex;justify-content:flex-end}.pdx-manual-form__assistant-trigger{border:0;border-radius:999px;padding:8px 14px;cursor:pointer;color:var(--md-sys-color-on-primary, #fff);background:var(--md-sys-color-primary, #3451d1);box-shadow:var(--md-sys-elevation-level2, 0 4px 12px rgba(0, 0, 0, .18))}.pdx-manual-form__assistant-trigger:hover{background:var(--md-sys-color-primary-container, #223fb6)}\n"] }]
3269
- }], ctorParameters: () => [], propDecorators: { formId: [{ type: i0.Input, args: [{ isSignal: true, alias: "formId", required: true }] }], formTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "formTitle", required: false }] }], formDescription: [{ type: i0.Input, args: [{ isSignal: true, alias: "formDescription", required: false }] }], actions: [{ type: i0.Input, args: [{ isSignal: true, alias: "actions", required: false }] }], showHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "showHeader", required: false }] }], showActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "showActions", required: false }] }], enableAutoSave: [{ type: i0.Input, args: [{ isSignal: true, alias: "enableAutoSave", required: false }] }], componentInstanceId: [{ type: i0.Input, args: [{ isSignal: true, alias: "componentInstanceId", required: false }] }], enableCustomization: [{ type: i0.Input, args: [{ isSignal: true, alias: "enableCustomization", required: false }] }], persistenceOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "persistenceOptions", required: false }] }], usePathNames: [{ type: i0.Input, args: [{ isSignal: true, alias: "usePathNames", required: false }] }], autoSaveDebounceMs: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoSaveDebounceMs", required: false }] }], submitted: [{ type: i0.Output, args: ["submitted"] }], saved: [{ type: i0.Output, args: ["saved"] }], resetEvent: [{ type: i0.Output, args: ["reset"] }], metadataChange: [{ type: i0.Output, args: ["metadataChange"] }], formControls: [{
4058
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"pdx-manual-form\">\n @if (showHeader()) {\n <praxis-manual-form-header [instance]=\"instance\" [title]=\"formTitle()\" [description]=\"formDescription()\"\n [enableCustomization]=\"enableCustomization()\" (editForm)=\"openFormEditor()\" (save)=\"handleSave()\"\n (reset)=\"handleReset()\"></praxis-manual-form-header>\n }\n\n @if (showAiAssistant() || enableCustomization()) {\n <div class=\"pdx-manual-form__assistant\">\n <button\n type=\"button\"\n class=\"pdx-manual-form__assistant-trigger\"\n (click)=\"openAiAssistant()\"\n [attr.aria-label]=\"enableCustomization() ? 'Abrir copiloto sem\u00E2ntico Praxis do formul\u00E1rio manual' : 'Abrir assistente de preenchimento do formul\u00E1rio manual'\"\n data-testid=\"praxis-manual-form-ai-assistant-trigger\"\n >\n {{ enableCustomization() ? 'Copiloto Praxis' : 'Assistente de preenchimento' }}\n </button>\n </div>\n }\n\n @if (aiAssistantOpen && aiAssistantViewState) {\n <praxis-ai-assistant-shell\n [labels]=\"aiAssistantLabels\"\n [mode]=\"aiAssistantViewState.mode\"\n [state]=\"aiAssistantViewState.state\"\n [contextItems]=\"aiAssistantViewState.contextItems\"\n [attachments]=\"aiAssistantViewState.attachments\"\n [messages]=\"aiAssistantViewState.messages\"\n [quickReplies]=\"aiAssistantViewState.quickReplies\"\n [prompt]=\"aiAssistantPrompt\"\n [statusText]=\"aiAssistantViewState.statusText\"\n [errorText]=\"aiAssistantViewState.errorText\"\n [busy]=\"aiAssistantViewState.state === 'processing' || aiAssistantViewState.state === 'applying'\"\n [canApply]=\"aiAssistantViewState.canApply\"\n [preview]=\"aiAssistantViewState.preview\"\n [layout]=\"aiAssistantLayout\"\n testIdPrefix=\"praxis-manual-form-ai-assistant\"\n (promptChange)=\"onAiAssistantPromptChange($event)\"\n (submitPrompt)=\"onAiAssistantSubmit($event)\"\n (apply)=\"onAiAssistantApply($event)\"\n (retryTurn)=\"onAiAssistantRetry()\"\n (cancelTurn)=\"onAiAssistantCancel()\"\n (close)=\"closeAiAssistant()\"\n (quickReply)=\"onAiAssistantQuickReply($event)\"\n (editMessage)=\"onAiAssistantEditMessage($event)\"\n (resendMessage)=\"onAiAssistantResendMessage($event)\"\n (layoutChange)=\"onAiAssistantLayoutChange($event)\"\n ></praxis-ai-assistant-shell>\n }\n\n <form class=\"pdx-manual-form__form\" [formGroup]=\"formGroup\" (submit)=\"handleSubmit(); $event.preventDefault()\">\n <ng-content></ng-content>\n </form>\n\n @if (showActions() && resolvedActions) {\n <praxis-manual-form-actions [actions]=\"resolvedActions\" [submitDisabled]=\"!effectiveFormIsValid\"\n (actionClick)=\"handleAction($event)\"></praxis-manual-form-actions>\n }\n</div>\n", styles: [".pdx-manual-form{display:flex;flex-direction:column;gap:var(--pdx-manual-form-gap, 24px);color:var(--md-sys-color-on-surface)}.pdx-manual-form__form{display:grid;gap:var(--pdx-manual-form-field-gap, 16px);padding:var(--pdx-manual-form-padding, 20px);border-radius:var(--pdx-manual-form-radius, 16px);background:var(--pdx-manual-form-surface, var(--md-sys-color-surface-container));border:1px solid var(--pdx-manual-form-outline, var(--md-sys-color-outline-variant));box-shadow:var(--pdx-manual-form-shadow, var(--md-sys-elevation-level1, none))}.pdx-manual-form__form:focus-within{border-color:var(--pdx-manual-form-focus, var(--md-sys-color-primary));box-shadow:0 0 0 2px var(--md-sys-color-primary),var(--pdx-manual-form-shadow, var(--md-sys-elevation-level1, none))}.pdx-manual-form__assistant{display:flex;justify-content:flex-end}.pdx-manual-form__assistant-trigger{border:0;border-radius:999px;padding:8px 14px;cursor:pointer;color:var(--md-sys-color-on-primary, #fff);background:var(--md-sys-color-primary, #3451d1);box-shadow:var(--md-sys-elevation-level2, 0 4px 12px rgba(0, 0, 0, .18))}.pdx-manual-form__assistant-trigger:hover{background:var(--md-sys-color-primary-container, #223fb6)}\n"] }]
4059
+ }], ctorParameters: () => [], propDecorators: { formId: [{ type: i0.Input, args: [{ isSignal: true, alias: "formId", required: true }] }], formTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "formTitle", required: false }] }], formDescription: [{ type: i0.Input, args: [{ isSignal: true, alias: "formDescription", required: false }] }], actions: [{ type: i0.Input, args: [{ isSignal: true, alias: "actions", required: false }] }], showHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "showHeader", required: false }] }], showActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "showActions", required: false }] }], enableAutoSave: [{ type: i0.Input, args: [{ isSignal: true, alias: "enableAutoSave", required: false }] }], componentInstanceId: [{ type: i0.Input, args: [{ isSignal: true, alias: "componentInstanceId", required: false }] }], showAiAssistant: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAiAssistant", required: false }] }], enableCustomization: [{ type: i0.Input, args: [{ isSignal: true, alias: "enableCustomization", required: false }] }], persistenceOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "persistenceOptions", required: false }] }], usePathNames: [{ type: i0.Input, args: [{ isSignal: true, alias: "usePathNames", required: false }] }], autoSaveDebounceMs: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoSaveDebounceMs", required: false }] }], resourcePath: [{ type: i0.Input, args: [{ isSignal: true, alias: "resourcePath", required: false }] }], governedSchema: [{ type: i0.Input, args: [{ isSignal: true, alias: "governedSchema", required: false }] }], schemaHash: [{ type: i0.Input, args: [{ isSignal: true, alias: "schemaHash", required: false }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], entityId: [{ type: i0.Input, args: [{ isSignal: true, alias: "entityId", required: false }] }], submitted: [{ type: i0.Output, args: ["submitted"] }], saved: [{ type: i0.Output, args: ["saved"] }], resetEvent: [{ type: i0.Output, args: ["reset"] }], metadataChange: [{ type: i0.Output, args: ["metadataChange"] }], formControls: [{
3270
4060
  type: ContentChildren,
3271
4061
  args: [FormControlName, { descendants: true }]
3272
4062
  }] } });
@@ -6101,7 +6891,7 @@ setCustomizationEnabled(enabled: boolean): void {
6101
6891
  </ol>
6102
6892
  </div>
6103
6893
  </praxis-manual-form-doc-example>
6104
- `, isInline: true, styles: [":host{display:block}.showcase-art{display:flex;gap:6px;flex-wrap:wrap}.showcase-art__chip{border-radius:999px;padding:4px 8px;font-size:11px;font-weight:700;border:1px solid color-mix(in srgb,var(--md-sys-color-outline, #98a3af) 50%,#d7dde3);background:color-mix(in srgb,var(--md-sys-color-primary, #00796b) 14%,#ffffff);color:var(--md-sys-color-on-surface, #151b22)}.showcase-live{display:grid;gap:12px}.showcase-mode{margin:0;border-radius:10px;border:1px solid #d6dde4;background:#f6f8fb;padding:8px 10px;color:#3b4651;font-size:13px}.showcase-mode--enabled{border-color:#5ebdb0;background:#e9f9f5;color:#075146}.showcase-field{display:grid;gap:6px}.showcase-field span{font-size:13px;font-weight:600}.showcase-field input,.showcase-field textarea{width:100%;border-radius:8px;border:1px solid #c8d2dc;padding:9px 10px;font:inherit;color:#1a222b;background:#fff}.showcase-field input:focus-visible,.showcase-field textarea:focus-visible{outline:2px solid #2d7f73;outline-offset:1px}.showcase-diagram{border-radius:12px;border:1px dashed #bdd0db;background:#f8fbff;padding:12px 14px}.showcase-diagram ol{margin:0;padding-left:20px;display:grid;gap:6px}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: ManualFormComponent, selector: "praxis-manual-form", inputs: ["formId", "formTitle", "formDescription", "actions", "showHeader", "showActions", "enableAutoSave", "componentInstanceId", "enableCustomization", "persistenceOptions", "usePathNames", "autoSaveDebounceMs"], outputs: ["submitted", "saved", "reset", "metadataChange"] }, { kind: "component", type: ManualFormDocExampleComponent, selector: "praxis-manual-form-doc-example", inputs: ["title", "subtitle", "level", "bannerTitle", "bannerDescription", "templateCode", "tsCode", "configCode", "customizationEnabled", "showCustomizationToggle", "important", "note", "tip"], outputs: ["tabChange", "customizationEnabledChange", "codeCopied"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
6894
+ `, isInline: true, styles: [":host{display:block}.showcase-art{display:flex;gap:6px;flex-wrap:wrap}.showcase-art__chip{border-radius:999px;padding:4px 8px;font-size:11px;font-weight:700;border:1px solid color-mix(in srgb,var(--md-sys-color-outline, #98a3af) 50%,#d7dde3);background:color-mix(in srgb,var(--md-sys-color-primary, #00796b) 14%,#ffffff);color:var(--md-sys-color-on-surface, #151b22)}.showcase-live{display:grid;gap:12px}.showcase-mode{margin:0;border-radius:10px;border:1px solid #d6dde4;background:#f6f8fb;padding:8px 10px;color:#3b4651;font-size:13px}.showcase-mode--enabled{border-color:#5ebdb0;background:#e9f9f5;color:#075146}.showcase-field{display:grid;gap:6px}.showcase-field span{font-size:13px;font-weight:600}.showcase-field input,.showcase-field textarea{width:100%;border-radius:8px;border:1px solid #c8d2dc;padding:9px 10px;font:inherit;color:#1a222b;background:#fff}.showcase-field input:focus-visible,.showcase-field textarea:focus-visible{outline:2px solid #2d7f73;outline-offset:1px}.showcase-diagram{border-radius:12px;border:1px dashed #bdd0db;background:#f8fbff;padding:12px 14px}.showcase-diagram ol{margin:0;padding-left:20px;display:grid;gap:6px}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: ManualFormComponent, selector: "praxis-manual-form", inputs: ["formId", "formTitle", "formDescription", "actions", "showHeader", "showActions", "enableAutoSave", "componentInstanceId", "showAiAssistant", "enableCustomization", "persistenceOptions", "usePathNames", "autoSaveDebounceMs", "resourcePath", "governedSchema", "schemaHash", "mode", "entityId"], outputs: ["submitted", "saved", "reset", "metadataChange"] }, { kind: "component", type: ManualFormDocExampleComponent, selector: "praxis-manual-form-doc-example", inputs: ["title", "subtitle", "level", "bannerTitle", "bannerDescription", "templateCode", "tsCode", "configCode", "customizationEnabled", "showCustomizationToggle", "important", "note", "tip"], outputs: ["tabChange", "customizationEnabledChange", "codeCopied"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
6105
6895
  }
6106
6896
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: ManualFormDocExampleShowcaseComponent, decorators: [{
6107
6897
  type: Component,
package/package.json CHANGED
@@ -1,19 +1,19 @@
1
1
  {
2
2
  "name": "@praxisui/manual-form",
3
- "version": "10.0.0-rc.40",
3
+ "version": "10.0.0-rc.42",
4
4
  "description": "Manual form toolkit for Praxis UI: container, instance factory and editor bridge for @praxisui/* fields.",
5
5
  "peerDependencies": {
6
6
  "@angular/common": "^21.0.0",
7
7
  "@angular/core": "^21.0.0",
8
- "@praxisui/core": "^10.0.0-rc.40",
9
- "@praxisui/dynamic-fields": "^10.0.0-rc.40",
10
- "@praxisui/settings-panel": "^10.0.0-rc.40",
11
- "@praxisui/metadata-editor": "^10.0.0-rc.40",
8
+ "@praxisui/core": "^10.0.0-rc.42",
9
+ "@praxisui/dynamic-fields": "^10.0.0-rc.42",
10
+ "@praxisui/settings-panel": "^10.0.0-rc.42",
11
+ "@praxisui/metadata-editor": "^10.0.0-rc.42",
12
12
  "@angular/cdk": "^21.0.0",
13
13
  "@angular/forms": "^21.0.0",
14
14
  "@angular/material": "^21.0.0",
15
15
  "@angular/router": "^21.0.0",
16
- "@praxisui/ai": "^10.0.0-rc.40",
16
+ "@praxisui/ai": "^10.0.0-rc.42",
17
17
  "rxjs": "~7.8.0"
18
18
  },
19
19
  "dependencies": {
@@ -1,4 +1,4 @@
1
- import { FormConfig, FieldMetadata, DynamicFormService, AsyncConfigStorage, FormActionsLayout, FormActionButton, AiCapability, FormMessagesLayout, FormBehaviorLayout, FormHookStage, FieldDefinition, FieldControlType, AiCapabilityCategory, AiCapabilityCatalog, AiValueKind, ComponentAuthoringManifest, ComponentDocMeta } from '@praxisui/core';
1
+ import { FormConfig, FieldMetadata, DynamicFormService, AsyncConfigStorage, FormActionsLayout, FormActionButton, AiCapability, PraxisRuntimeFormValueTargetIdentity, PraxisRuntimeFormValueEligibility, PraxisRuntimeFormValueProposal, PraxisRuntimeFormValueApplyMode, PraxisRuntimeFormValuePreviewResult, PraxisRuntimeFormValueApplyRequest, PraxisRuntimeFormValueApplyReceipt, PraxisRuntimeFormValueUndoReceipt, PraxisRuntimeFormValueTargetPort, PraxisRuntimeFormValueMode, FormMessagesLayout, FormBehaviorLayout, FormHookStage, FieldDefinition, FieldControlType, AiCapabilityCategory, AiCapabilityCatalog, AiValueKind, ComponentAuthoringManifest, ComponentDocMeta } from '@praxisui/core';
2
2
  import { FormGroup, FormControlName, FormGroupName, AbstractControl, FormControl } from '@angular/forms';
3
3
  import { Observable, BehaviorSubject } from 'rxjs';
4
4
  import * as _angular_core from '@angular/core';
@@ -144,12 +144,13 @@ declare class ManualFormHeaderComponent {
144
144
 
145
145
  declare class ManualFormActionsComponent {
146
146
  readonly actions: _angular_core.InputSignal<FormActionsLayout | null | undefined>;
147
+ readonly submitDisabled: _angular_core.InputSignal<boolean>;
147
148
  trackByFn: ((idx: number, item: FormActionButton) => unknown) | null;
148
149
  readonly actionClick: _angular_core.OutputEmitterRef<string>;
149
150
  isVisible(action?: FormActionButton | null): boolean;
150
151
  emit(kind: string, action?: FormActionButton | null): void;
151
152
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<ManualFormActionsComponent, never>;
152
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<ManualFormActionsComponent, "praxis-manual-form-actions", never, { "actions": { "alias": "actions"; "required": false; "isSignal": true; }; "trackByFn": { "alias": "trackByFn"; "required": false; }; }, { "actionClick": "actionClick"; }, never, never, true, never>;
153
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<ManualFormActionsComponent, "praxis-manual-form-actions", never, { "actions": { "alias": "actions"; "required": false; "isSignal": true; }; "submitDisabled": { "alias": "submitDisabled"; "required": false; "isSignal": true; }; "trackByFn": { "alias": "trackByFn"; "required": false; }; }, { "actionClick": "actionClick"; }, never, never, true, never>;
153
154
  }
154
155
 
155
156
  declare class ManualFormAiAdapter extends BaseAiAdapter<FormConfig> {
@@ -164,6 +165,15 @@ declare class ManualFormAiAdapter extends BaseAiAdapter<FormConfig> {
164
165
  getDataProfile(): Record<string, any>;
165
166
  getSchemaFields(): Record<string, any>[];
166
167
  getAuthoringContext(): Record<string, any>;
168
+ private resolveGovernedSchemaPayload;
169
+ getRuntimeValueTargetIdentity(): PraxisRuntimeFormValueTargetIdentity | null;
170
+ getRuntimeValueEligibility(): PraxisRuntimeFormValueEligibility | null;
171
+ previewRuntimeValues(proposal: PraxisRuntimeFormValueProposal, options?: {
172
+ readonly selectedFieldPaths?: readonly string[];
173
+ readonly applyMode?: PraxisRuntimeFormValueApplyMode;
174
+ }): PraxisRuntimeFormValuePreviewResult | null;
175
+ applyRuntimeValues(request: PraxisRuntimeFormValueApplyRequest): Promise<PraxisRuntimeFormValueApplyReceipt | null>;
176
+ undoRuntimeValues(receiptId?: string): Promise<PraxisRuntimeFormValueUndoReceipt | null>;
167
177
  createSnapshot(): FormConfig;
168
178
  restoreSnapshot(snapshot: FormConfig): Promise<void>;
169
179
  applyPatch(patch: Partial<FormConfig>, _intent?: string): Promise<PatchResult>;
@@ -173,7 +183,7 @@ declare class ManualFormAiAdapter extends BaseAiAdapter<FormConfig> {
173
183
  private safeFormId;
174
184
  }
175
185
 
176
- declare class ManualFormComponent implements AfterContentInit, OnDestroy {
186
+ declare class ManualFormComponent implements AfterContentInit, OnDestroy, PraxisRuntimeFormValueTargetPort {
177
187
  private readonly instanceFactory;
178
188
  private readonly cdr;
179
189
  private readonly destroyRef;
@@ -210,10 +220,16 @@ declare class ManualFormComponent implements AfterContentInit, OnDestroy {
210
220
  readonly showActions: _angular_core.InputSignal<boolean>;
211
221
  readonly enableAutoSave: _angular_core.InputSignal<boolean>;
212
222
  readonly componentInstanceId: _angular_core.InputSignal<string | undefined>;
223
+ readonly showAiAssistant: _angular_core.InputSignal<boolean>;
213
224
  readonly enableCustomization: _angular_core.InputSignal<boolean>;
214
225
  readonly persistenceOptions: _angular_core.InputSignal<ManualFormPersistenceOptions | undefined>;
215
226
  readonly usePathNames: _angular_core.InputSignal<boolean>;
216
227
  readonly autoSaveDebounceMs: _angular_core.InputSignal<number>;
228
+ readonly resourcePath: _angular_core.InputSignal<string | undefined>;
229
+ readonly governedSchema: _angular_core.InputSignal<Record<string, unknown> | readonly FieldMetadata[] | null | undefined>;
230
+ readonly schemaHash: _angular_core.InputSignal<string | undefined>;
231
+ readonly mode: _angular_core.InputSignal<PraxisRuntimeFormValueMode>;
232
+ readonly entityId: _angular_core.InputSignal<string | number | null | undefined>;
217
233
  readonly submitted: _angular_core.OutputEmitterRef<{
218
234
  value: any;
219
235
  instance: ManualFormInstance;
@@ -235,9 +251,16 @@ declare class ManualFormComponent implements AfterContentInit, OnDestroy {
235
251
  private aiAssistantStateSubscription;
236
252
  formGroup: FormGroup;
237
253
  private readonly registeredDirectives;
254
+ private readonly runtimeValueJournal;
255
+ private runtimeValueRevision;
256
+ private runtimeValueTrackedForm;
257
+ private runtimeValueStatusSub?;
258
+ private readonly runtimeValueTrackedControls;
259
+ private suppressRuntimeValueTrackingDepth;
238
260
  constructor();
239
261
  ngAfterContentInit(): void;
240
262
  ngOnDestroy(): void;
263
+ get effectiveFormIsValid(): boolean;
241
264
  get formDirective(): any;
242
265
  get control(): FormGroup;
243
266
  get path(): any[];
@@ -268,7 +291,7 @@ declare class ManualFormComponent implements AfterContentInit, OnDestroy {
268
291
  closeAiAssistant(): void;
269
292
  onAiAssistantPromptChange(prompt: string): void;
270
293
  onAiAssistantSubmit(prompt: string): void;
271
- onAiAssistantApply(): void;
294
+ onAiAssistantApply(contextHints?: Record<string, unknown> | void): void;
272
295
  onAiAssistantRetry(): void;
273
296
  onAiAssistantCancel(): void;
274
297
  onAiAssistantQuickReply(reply: PraxisAssistantShellQuickReply): void;
@@ -324,8 +347,23 @@ declare class ManualFormComponent implements AfterContentInit, OnDestroy {
324
347
  private applyMetadataToComponent;
325
348
  private buildCurrentConfigSnapshot;
326
349
  private normalizeActions;
350
+ getRuntimeValueTargetIdentity(): PraxisRuntimeFormValueTargetIdentity;
351
+ getRuntimeValueEligibility(): PraxisRuntimeFormValueEligibility;
352
+ previewRuntimeValues(proposal: PraxisRuntimeFormValueProposal, options?: {
353
+ readonly selectedFieldPaths?: readonly string[];
354
+ readonly applyMode?: PraxisRuntimeFormValueApplyMode;
355
+ }): PraxisRuntimeFormValuePreviewResult;
356
+ applyRuntimeValues(request: PraxisRuntimeFormValueApplyRequest): PraxisRuntimeFormValueApplyReceipt;
357
+ undoRuntimeValues(receiptId?: string): PraxisRuntimeFormValueUndoReceipt;
358
+ private clearRuntimeValueControlSubscriptions;
359
+ private collectLeafFormControls;
360
+ private ensureRuntimeValueTracking;
361
+ private createRuntimeFormHostCallbacks;
362
+ private extractGovernedSchemaHash;
363
+ private extractGovernedFieldMap;
364
+ private collectRuntimeValueFieldClassification;
327
365
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<ManualFormComponent, never>;
328
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<ManualFormComponent, "praxis-manual-form", never, { "formId": { "alias": "formId"; "required": true; "isSignal": true; }; "formTitle": { "alias": "formTitle"; "required": false; "isSignal": true; }; "formDescription": { "alias": "formDescription"; "required": false; "isSignal": true; }; "actions": { "alias": "actions"; "required": false; "isSignal": true; }; "showHeader": { "alias": "showHeader"; "required": false; "isSignal": true; }; "showActions": { "alias": "showActions"; "required": false; "isSignal": true; }; "enableAutoSave": { "alias": "enableAutoSave"; "required": false; "isSignal": true; }; "componentInstanceId": { "alias": "componentInstanceId"; "required": false; "isSignal": true; }; "enableCustomization": { "alias": "enableCustomization"; "required": false; "isSignal": true; }; "persistenceOptions": { "alias": "persistenceOptions"; "required": false; "isSignal": true; }; "usePathNames": { "alias": "usePathNames"; "required": false; "isSignal": true; }; "autoSaveDebounceMs": { "alias": "autoSaveDebounceMs"; "required": false; "isSignal": true; }; }, { "submitted": "submitted"; "saved": "saved"; "resetEvent": "reset"; "metadataChange": "metadataChange"; }, ["formControls"], ["*"], true, never>;
366
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<ManualFormComponent, "praxis-manual-form", never, { "formId": { "alias": "formId"; "required": true; "isSignal": true; }; "formTitle": { "alias": "formTitle"; "required": false; "isSignal": true; }; "formDescription": { "alias": "formDescription"; "required": false; "isSignal": true; }; "actions": { "alias": "actions"; "required": false; "isSignal": true; }; "showHeader": { "alias": "showHeader"; "required": false; "isSignal": true; }; "showActions": { "alias": "showActions"; "required": false; "isSignal": true; }; "enableAutoSave": { "alias": "enableAutoSave"; "required": false; "isSignal": true; }; "componentInstanceId": { "alias": "componentInstanceId"; "required": false; "isSignal": true; }; "showAiAssistant": { "alias": "showAiAssistant"; "required": false; "isSignal": true; }; "enableCustomization": { "alias": "enableCustomization"; "required": false; "isSignal": true; }; "persistenceOptions": { "alias": "persistenceOptions"; "required": false; "isSignal": true; }; "usePathNames": { "alias": "usePathNames"; "required": false; "isSignal": true; }; "autoSaveDebounceMs": { "alias": "autoSaveDebounceMs"; "required": false; "isSignal": true; }; "resourcePath": { "alias": "resourcePath"; "required": false; "isSignal": true; }; "governedSchema": { "alias": "governedSchema"; "required": false; "isSignal": true; }; "schemaHash": { "alias": "schemaHash"; "required": false; "isSignal": true; }; "mode": { "alias": "mode"; "required": false; "isSignal": true; }; "entityId": { "alias": "entityId"; "required": false; "isSignal": true; }; }, { "submitted": "submitted"; "saved": "saved"; "resetEvent": "reset"; "metadataChange": "metadataChange"; }, ["formControls"], ["*"], true, never>;
329
367
  }
330
368
 
331
369
  interface PanelInputs {