@praxisui/dynamic-form 10.0.0-rc.39 → 10.0.0-rc.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": "1.0.0",
3
- "generatedAt": "2026-10-26T17:40:14.409Z",
3
+ "generatedAt": "2026-10-26T18:09:20.136Z",
4
4
  "packageName": "@praxisui/dynamic-form",
5
- "packageVersion": "10.0.0-rc.39",
5
+ "packageVersion": "10.0.0-rc.40",
6
6
  "sourceRegistry": "praxis-component-registry-ingestion",
7
7
  "sourceRegistryVersion": "1.0.0",
8
8
  "componentCount": 2,
@@ -1484,6 +1484,329 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
1484
1484
  }]
1485
1485
  }], ctorParameters: () => [{ type: i1.DomainRuleService }] });
1486
1486
 
1487
+ /**
1488
+ * Recursively converts arrays representing dates into ISO-8601 strings.
1489
+ * Arrays are expected in the form `[year, month, day, hour?, minute?, second?, millisecond?]`.
1490
+ * Non-date arrays and other values are returned untouched.
1491
+ */
1492
+ function normalizeDateArrays(data) {
1493
+ if (data instanceof Date) {
1494
+ return data;
1495
+ }
1496
+ if (Array.isArray(data)) {
1497
+ if (isDateArray(data)) {
1498
+ return formatDateArray(data);
1499
+ }
1500
+ return data.map((v) => normalizeDateArrays(v));
1501
+ }
1502
+ if (data && typeof data === 'object') {
1503
+ const result = {};
1504
+ for (const [key, value] of Object.entries(data)) {
1505
+ result[key] = normalizeDateArrays(value);
1506
+ }
1507
+ return result;
1508
+ }
1509
+ return data;
1510
+ }
1511
+ function isDateArray(arr) {
1512
+ if (arr.length < 3 || arr.length > 7)
1513
+ return false;
1514
+ return (arr.every((n) => typeof n === 'number') && arr[0] >= 1000 && arr[0] <= 9999);
1515
+ }
1516
+ function pad$1(value, size) {
1517
+ return String(value).padStart(size, '0');
1518
+ }
1519
+ function formatDateArray(arr) {
1520
+ const [y, m, d, h = 0, min = 0, s = 0, ms = 0] = arr;
1521
+ const datePart = `${y}-${pad$1(m, 2)}-${pad$1(d, 2)}`;
1522
+ if (arr.length > 3) {
1523
+ const timePart = `${pad$1(h, 2)}:${pad$1(min, 2)}:${pad$1(s, 2)}`;
1524
+ return arr.length > 6
1525
+ ? `${datePart}T${timePart}.${pad$1(ms, 3)}`
1526
+ : `${datePart}T${timePart}`;
1527
+ }
1528
+ return datePart;
1529
+ }
1530
+
1531
+ const ISO_LOCAL_DATETIME_PATTERN = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2}(?:\.\d{1,3})?)?$/;
1532
+ const ISO_OFFSET_OR_Z_SUFFIX_PATTERN = /(Z|[+\-]\d{2}:\d{2})$/i;
1533
+ function normalizeSubmitPayload(data) {
1534
+ return normalizeTemporalStrings(normalizeDateArrays(data));
1535
+ }
1536
+ function normalizeTemporalStrings(value) {
1537
+ // Date-only fields are converted by the field-aware submit pipeline. Keep
1538
+ // native Date values intact here instead of treating them as generic records
1539
+ // (which would otherwise turn them into an empty object).
1540
+ if (value instanceof Date) {
1541
+ return value;
1542
+ }
1543
+ if (Array.isArray(value)) {
1544
+ return value.map((item) => normalizeTemporalStrings(item));
1545
+ }
1546
+ if (value && typeof value === 'object') {
1547
+ const normalized = {};
1548
+ for (const [key, nested] of Object.entries(value)) {
1549
+ normalized[key] = normalizeTemporalStrings(nested);
1550
+ }
1551
+ return normalized;
1552
+ }
1553
+ if (typeof value === 'string') {
1554
+ return normalizeLocalDateTimeString(value);
1555
+ }
1556
+ return value;
1557
+ }
1558
+ function normalizeLocalDateTimeString(value) {
1559
+ const trimmed = String(value || '').trim();
1560
+ if (!trimmed) {
1561
+ return trimmed;
1562
+ }
1563
+ if (!ISO_LOCAL_DATETIME_PATTERN.test(trimmed) || ISO_OFFSET_OR_Z_SUFFIX_PATTERN.test(trimmed)) {
1564
+ return trimmed;
1565
+ }
1566
+ const parsed = parseLocalDateTime(trimmed);
1567
+ if (!parsed) {
1568
+ return trimmed;
1569
+ }
1570
+ const offset = buildIsoOffset(parsed.date.getTimezoneOffset());
1571
+ return `${parsed.datePart}T${parsed.timePart}${offset}`;
1572
+ }
1573
+ function parseLocalDateTime(value) {
1574
+ const [datePart, rawTimePart] = value.split('T');
1575
+ if (!datePart || !rawTimePart) {
1576
+ return null;
1577
+ }
1578
+ const [year, month, day] = datePart.split('-').map((token) => Number(token));
1579
+ const [timeMain, fractionalPart = ''] = rawTimePart.split('.');
1580
+ const [hour, minute, second = 0] = timeMain.split(':').map((token) => Number(token));
1581
+ const millisecond = Number((fractionalPart + '000').slice(0, 3));
1582
+ const date = new Date(year, month - 1, day, hour, minute, second, millisecond);
1583
+ if (Number.isNaN(date.getTime())) {
1584
+ return null;
1585
+ }
1586
+ const normalizedDatePart = `${datePart}`;
1587
+ const normalizedTimePart = fractionalPart.length > 0
1588
+ ? `${pad(hour)}:${pad(minute)}:${pad(second)}.${fractionalPart}`
1589
+ : `${pad(hour)}:${pad(minute)}:${pad(second)}`;
1590
+ return {
1591
+ date,
1592
+ datePart: normalizedDatePart,
1593
+ timePart: normalizedTimePart,
1594
+ };
1595
+ }
1596
+ function buildIsoOffset(timezoneOffsetMinutes) {
1597
+ const totalMinutes = -timezoneOffsetMinutes;
1598
+ const sign = totalMinutes >= 0 ? '+' : '-';
1599
+ const absoluteMinutes = Math.abs(totalMinutes);
1600
+ const hours = Math.floor(absoluteMinutes / 60);
1601
+ const minutes = absoluteMinutes % 60;
1602
+ return `${sign}${pad(hours)}:${pad(minutes)}`;
1603
+ }
1604
+ function pad(value) {
1605
+ return String(value).padStart(2, '0');
1606
+ }
1607
+
1608
+ function prepareSubmitPayload(rawValue, fieldMetadata, options = {}) {
1609
+ const normalized = normalizeSubmitPayload(rawValue);
1610
+ if (!normalized || typeof normalized !== 'object' || Array.isArray(normalized)) {
1611
+ return normalized;
1612
+ }
1613
+ const dirtyFields = new Set(options.dirtyFields || []);
1614
+ return filterRecordForSubmit(normalized, fieldMetadata || [], dirtyFields);
1615
+ }
1616
+ function shouldOmitEmptyOptionalField(field, value, dirtyFields, scopePath) {
1617
+ if (isFieldDirty(field.name, dirtyFields, scopePath) || isRequiredField(field)) {
1618
+ return false;
1619
+ }
1620
+ return value === null || value === undefined || value === '';
1621
+ }
1622
+ function isRequiredField(field) {
1623
+ const validators = field.validators;
1624
+ return field.required === true || validators?.required === true;
1625
+ }
1626
+ function shouldOmitFieldFromSubmit(field, dirtyFields = new Set(), scopePath) {
1627
+ const policy = normalizeSubmitPolicy(field.submitPolicy);
1628
+ if (policy) {
1629
+ return shouldOmitByPolicy(policy, field.name, dirtyFields, scopePath);
1630
+ }
1631
+ return field.source === 'local' || field.transient === true;
1632
+ }
1633
+ function normalizeSubmitPolicy(policy) {
1634
+ if (policy === 'include' || policy === 'omit' || policy === 'includeWhenDirty') {
1635
+ return policy;
1636
+ }
1637
+ // Defensive runtime migration for JSON/LLM/configs that may use the old
1638
+ // wording. The persisted/public contract remains `omit`.
1639
+ if (policy === 'never') {
1640
+ return 'omit';
1641
+ }
1642
+ return undefined;
1643
+ }
1644
+ function shouldOmitByPolicy(policy, fieldName, dirtyFields, scopePath) {
1645
+ switch (policy) {
1646
+ case 'include':
1647
+ return false;
1648
+ case 'omit':
1649
+ return true;
1650
+ case 'includeWhenDirty':
1651
+ return !isFieldDirty(fieldName, dirtyFields, scopePath);
1652
+ default:
1653
+ return false;
1654
+ }
1655
+ }
1656
+ function filterRecordForSubmit(value, fields, dirtyFields, scopePath) {
1657
+ const payload = { ...value };
1658
+ for (const field of fields) {
1659
+ if (shouldOmitFieldFromSubmit(field, dirtyFields, scopePath)) {
1660
+ delete payload[field.name];
1661
+ continue;
1662
+ }
1663
+ const fieldValue = payload[field.name];
1664
+ const fieldPath = buildScopedFieldPath(field.name, scopePath);
1665
+ payload[field.name] = normalizeFieldValueForSubmit(field, fieldValue, dirtyFields, fieldPath);
1666
+ if (shouldOmitEmptyOptionalField(field, payload[field.name], dirtyFields, scopePath)) {
1667
+ delete payload[field.name];
1668
+ }
1669
+ }
1670
+ return payload;
1671
+ }
1672
+ function normalizeFieldValueForSubmit(field, value, dirtyFields, fieldPath) {
1673
+ const normalizedScalarOrRef = normalizeFieldValueForRequestPayload(field, value);
1674
+ return filterNestedArrayForSubmit(field, normalizedScalarOrRef, dirtyFields, fieldPath);
1675
+ }
1676
+ /**
1677
+ * Projects a single field control value into its request-schema representation
1678
+ * (ISO-8601 date for date-only fields and scalar ID / EntityRef for entity-lookup
1679
+ * controls). Shared by submit payload serialization and reactive determination
1680
+ * request bindings so UI presentation wrappers never leak into backend requests.
1681
+ */
1682
+ function normalizeFieldValueForRequestPayload(field, value) {
1683
+ if (field) {
1684
+ const normalizedDateValue = normalizeDateOnlyFieldValueForSubmit(field, value);
1685
+ return normalizeEntityLookupValueForSubmit(field, normalizedDateValue);
1686
+ }
1687
+ if (isEntityLookupResultObject(value)) {
1688
+ return serializeEntityLookupValueForPayload(value);
1689
+ }
1690
+ return value;
1691
+ }
1692
+ /**
1693
+ * Projects date-only controls into the ISO-8601 representation required by
1694
+ * OpenAPI `format: date` / Java `LocalDate` contracts. A date field may hold
1695
+ * a native Date (calendar selection) or its locale display value (manual
1696
+ * masked input); neither presentation value should leak into the request.
1697
+ */
1698
+ function normalizeDateOnlyFieldValueForSubmit(field, value) {
1699
+ if (!isDateOnlyField(field) || value === null || value === undefined || value === '') {
1700
+ return value;
1701
+ }
1702
+ if (value instanceof Date) {
1703
+ return isValidDate(value) ? formatLocalIsoDate(value) : value;
1704
+ }
1705
+ if (typeof value !== 'string') {
1706
+ return value;
1707
+ }
1708
+ const trimmed = value.trim();
1709
+ if (isIsoDate(trimmed)) {
1710
+ return trimmed;
1711
+ }
1712
+ const parsed = parseDayFirstDate(trimmed, field);
1713
+ return parsed ? formatLocalIsoDate(parsed) : value;
1714
+ }
1715
+ function isDateOnlyField(field) {
1716
+ const dataType = String(field.dataType ?? '').trim().toLowerCase();
1717
+ if (dataType === 'date') {
1718
+ return true;
1719
+ }
1720
+ const controlType = String(field.controlType ?? '').trim().toLowerCase();
1721
+ return controlType === 'date' || controlType === 'datepicker' || controlType === 'date_picker';
1722
+ }
1723
+ function isIsoDate(value) {
1724
+ return /^\d{4}-\d{2}-\d{2}$/.test(value);
1725
+ }
1726
+ function parseDayFirstDate(value, field) {
1727
+ const displayFormat = String(field.displayFormat ?? field.mask ?? '').toLowerCase();
1728
+ if (!displayFormat.includes('dd') || !displayFormat.includes('mm') || !displayFormat.includes('yyyy')) {
1729
+ return null;
1730
+ }
1731
+ const match = /^(\d{1,2})\/(\d{1,2})\/(\d{4})$/.exec(value);
1732
+ if (!match) {
1733
+ return null;
1734
+ }
1735
+ const day = Number(match[1]);
1736
+ const month = Number(match[2]);
1737
+ const year = Number(match[3]);
1738
+ const parsed = new Date(year, month - 1, day);
1739
+ return isValidDate(parsed) &&
1740
+ parsed.getFullYear() === year &&
1741
+ parsed.getMonth() === month - 1 &&
1742
+ parsed.getDate() === day
1743
+ ? parsed
1744
+ : null;
1745
+ }
1746
+ function isValidDate(value) {
1747
+ return !Number.isNaN(value.getTime());
1748
+ }
1749
+ function formatLocalIsoDate(value) {
1750
+ const year = value.getFullYear();
1751
+ const month = String(value.getMonth() + 1).padStart(2, '0');
1752
+ const day = String(value.getDate()).padStart(2, '0');
1753
+ return `${year}-${month}-${day}`;
1754
+ }
1755
+ function normalizeEntityLookupValueForSubmit(field, value) {
1756
+ if (!isEntityLookupField(field) && !isEntityLookupResultObject(value)) {
1757
+ return value;
1758
+ }
1759
+ return serializeEntityLookupValueForPayload(value, {
1760
+ payloadMode: field.payloadMode,
1761
+ multiple: field.multiple === true,
1762
+ entityType: field.optionSource?.entityKey?.trim(),
1763
+ });
1764
+ }
1765
+ function isEntityLookupResultObject(value) {
1766
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
1767
+ return false;
1768
+ }
1769
+ const record = value;
1770
+ return (Object.prototype.hasOwnProperty.call(record, 'id') &&
1771
+ typeof record['label'] === 'string' &&
1772
+ typeof record['extra'] === 'object' &&
1773
+ record['extra'] !== null);
1774
+ }
1775
+ function filterNestedArrayForSubmit(field, value, dirtyFields, fieldPath) {
1776
+ const itemFields = field.array?.itemSchema?.fields;
1777
+ if (!Array.isArray(value) || !itemFields?.length) {
1778
+ return value;
1779
+ }
1780
+ return value.map((item, index) => {
1781
+ if (!item || typeof item !== 'object' || Array.isArray(item)) {
1782
+ return item;
1783
+ }
1784
+ return filterRecordForSubmit(item, itemFields, dirtyFields, `${fieldPath}.${index}`);
1785
+ });
1786
+ }
1787
+ function isFieldDirty(fieldName, dirtyFields, scopePath) {
1788
+ if (dirtyFields.has(fieldName)) {
1789
+ return true;
1790
+ }
1791
+ if (!scopePath) {
1792
+ return false;
1793
+ }
1794
+ return (dirtyFields.has(scopePath) ||
1795
+ dirtyFields.has(buildScopedFieldPath(fieldName, scopePath)) ||
1796
+ dirtyFields.has(buildBracketScopedFieldPath(fieldName, scopePath)));
1797
+ }
1798
+ function buildScopedFieldPath(fieldName, scopePath) {
1799
+ return scopePath ? `${scopePath}.${fieldName}` : fieldName;
1800
+ }
1801
+ function buildBracketScopedFieldPath(fieldName, scopePath) {
1802
+ const bracketPath = scopePath.replace(/\.(\d+)(?=\.|$)/g, '[$1]');
1803
+ return `${bracketPath}.${fieldName}`;
1804
+ }
1805
+ function isEntityLookupField(field) {
1806
+ return (field.controlType === 'entityLookup' ||
1807
+ field.controlType === 'inlineEntityLookup');
1808
+ }
1809
+
1487
1810
  const DEFAULT_DEBOUNCE_MS = 300;
1488
1811
  const DEFAULT_OPERATION_TIMEOUT_MS = 30_000;
1489
1812
  const SAFE_URL_BASE = 'https://praxis.invalid';
@@ -1534,7 +1857,7 @@ class ReactiveDeterminationRuntimeService {
1534
1857
  isOwnedTarget(form, control) {
1535
1858
  return this.ownedTargetsByForm.get(form)?.has(control) === true;
1536
1859
  }
1537
- connect(form, definitions, executor, onEvent, operationTimeoutMs = DEFAULT_OPERATION_TIMEOUT_MS) {
1860
+ connect(form, definitions, executor, onEvent, operationTimeoutMs = DEFAULT_OPERATION_TIMEOUT_MS, fieldMetadata) {
1538
1861
  const composite = new Subscription();
1539
1862
  const pendingCorrelations = new Set();
1540
1863
  const publishEvent = (event) => {
@@ -1643,7 +1966,7 @@ class ReactiveDeterminationRuntimeService {
1643
1966
  }
1644
1967
  let invocation;
1645
1968
  try {
1646
- invocation = this.buildInvocation(form, definition);
1969
+ invocation = this.buildInvocation(form, definition, fieldMetadata);
1647
1970
  }
1648
1971
  catch {
1649
1972
  publishEvent(this.event(definition, 'error', signal.correlationId, 0, 'request-binding-invalid'));
@@ -1750,15 +2073,21 @@ class ReactiveDeterminationRuntimeService {
1750
2073
  this.ownedTargetsByForm.delete(form);
1751
2074
  };
1752
2075
  }
1753
- buildInvocation(form, definition) {
2076
+ buildInvocation(form, definition, fieldMetadata) {
1754
2077
  const body = Object.create(null);
1755
2078
  const fingerprintValues = [];
1756
2079
  for (const binding of definition.inputs) {
1757
- const control = form.get(jsonPointerSegments(binding.fieldPath));
1758
- if (!control || !writeJsonPointer(body, binding.requestPath, control.value)) {
2080
+ const segments = jsonPointerSegments(binding.fieldPath);
2081
+ const control = form.get(segments);
2082
+ if (!control) {
1759
2083
  throw new InvalidReactiveDeterminationBindingError();
1760
2084
  }
1761
- fingerprintValues.push(control.value);
2085
+ const field = resolveFieldMetadataForSegments(fieldMetadata, segments);
2086
+ const normalizedValue = normalizeFieldValueForRequestPayload(field, control.value);
2087
+ if (!writeJsonPointer(body, binding.requestPath, normalizedValue)) {
2088
+ throw new InvalidReactiveDeterminationBindingError();
2089
+ }
2090
+ fingerprintValues.push(normalizedValue);
1762
2091
  }
1763
2092
  return { body, fingerprint: stableFingerprint(fingerprintValues) };
1764
2093
  }
@@ -2018,6 +2347,11 @@ function isSafeOperationPath(path) {
2018
2347
  return false;
2019
2348
  }
2020
2349
  }
2350
+ function resolveFieldMetadataForSegments(fields, segments) {
2351
+ if (!fields?.length || segments.length !== 1)
2352
+ return undefined;
2353
+ return fields.find((field) => field.name === segments[0]);
2354
+ }
2021
2355
  function stableFingerprint(value) {
2022
2356
  try {
2023
2357
  return JSON.stringify(value);
@@ -2043,304 +2377,6 @@ function createCorrelationId() {
2043
2377
  return `reactive-determination-${Date.now()}-${Math.random().toString(16).slice(2)}`;
2044
2378
  }
2045
2379
 
2046
- /**
2047
- * Recursively converts arrays representing dates into ISO-8601 strings.
2048
- * Arrays are expected in the form `[year, month, day, hour?, minute?, second?, millisecond?]`.
2049
- * Non-date arrays and other values are returned untouched.
2050
- */
2051
- function normalizeDateArrays(data) {
2052
- if (data instanceof Date) {
2053
- return data;
2054
- }
2055
- if (Array.isArray(data)) {
2056
- if (isDateArray(data)) {
2057
- return formatDateArray(data);
2058
- }
2059
- return data.map((v) => normalizeDateArrays(v));
2060
- }
2061
- if (data && typeof data === 'object') {
2062
- const result = {};
2063
- for (const [key, value] of Object.entries(data)) {
2064
- result[key] = normalizeDateArrays(value);
2065
- }
2066
- return result;
2067
- }
2068
- return data;
2069
- }
2070
- function isDateArray(arr) {
2071
- if (arr.length < 3 || arr.length > 7)
2072
- return false;
2073
- return (arr.every((n) => typeof n === 'number') && arr[0] >= 1000 && arr[0] <= 9999);
2074
- }
2075
- function pad$1(value, size) {
2076
- return String(value).padStart(size, '0');
2077
- }
2078
- function formatDateArray(arr) {
2079
- const [y, m, d, h = 0, min = 0, s = 0, ms = 0] = arr;
2080
- const datePart = `${y}-${pad$1(m, 2)}-${pad$1(d, 2)}`;
2081
- if (arr.length > 3) {
2082
- const timePart = `${pad$1(h, 2)}:${pad$1(min, 2)}:${pad$1(s, 2)}`;
2083
- return arr.length > 6
2084
- ? `${datePart}T${timePart}.${pad$1(ms, 3)}`
2085
- : `${datePart}T${timePart}`;
2086
- }
2087
- return datePart;
2088
- }
2089
-
2090
- const ISO_LOCAL_DATETIME_PATTERN = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2}(?:\.\d{1,3})?)?$/;
2091
- const ISO_OFFSET_OR_Z_SUFFIX_PATTERN = /(Z|[+\-]\d{2}:\d{2})$/i;
2092
- function normalizeSubmitPayload(data) {
2093
- return normalizeTemporalStrings(normalizeDateArrays(data));
2094
- }
2095
- function normalizeTemporalStrings(value) {
2096
- // Date-only fields are converted by the field-aware submit pipeline. Keep
2097
- // native Date values intact here instead of treating them as generic records
2098
- // (which would otherwise turn them into an empty object).
2099
- if (value instanceof Date) {
2100
- return value;
2101
- }
2102
- if (Array.isArray(value)) {
2103
- return value.map((item) => normalizeTemporalStrings(item));
2104
- }
2105
- if (value && typeof value === 'object') {
2106
- const normalized = {};
2107
- for (const [key, nested] of Object.entries(value)) {
2108
- normalized[key] = normalizeTemporalStrings(nested);
2109
- }
2110
- return normalized;
2111
- }
2112
- if (typeof value === 'string') {
2113
- return normalizeLocalDateTimeString(value);
2114
- }
2115
- return value;
2116
- }
2117
- function normalizeLocalDateTimeString(value) {
2118
- const trimmed = String(value || '').trim();
2119
- if (!trimmed) {
2120
- return trimmed;
2121
- }
2122
- if (!ISO_LOCAL_DATETIME_PATTERN.test(trimmed) || ISO_OFFSET_OR_Z_SUFFIX_PATTERN.test(trimmed)) {
2123
- return trimmed;
2124
- }
2125
- const parsed = parseLocalDateTime(trimmed);
2126
- if (!parsed) {
2127
- return trimmed;
2128
- }
2129
- const offset = buildIsoOffset(parsed.date.getTimezoneOffset());
2130
- return `${parsed.datePart}T${parsed.timePart}${offset}`;
2131
- }
2132
- function parseLocalDateTime(value) {
2133
- const [datePart, rawTimePart] = value.split('T');
2134
- if (!datePart || !rawTimePart) {
2135
- return null;
2136
- }
2137
- const [year, month, day] = datePart.split('-').map((token) => Number(token));
2138
- const [timeMain, fractionalPart = ''] = rawTimePart.split('.');
2139
- const [hour, minute, second = 0] = timeMain.split(':').map((token) => Number(token));
2140
- const millisecond = Number((fractionalPart + '000').slice(0, 3));
2141
- const date = new Date(year, month - 1, day, hour, minute, second, millisecond);
2142
- if (Number.isNaN(date.getTime())) {
2143
- return null;
2144
- }
2145
- const normalizedDatePart = `${datePart}`;
2146
- const normalizedTimePart = fractionalPart.length > 0
2147
- ? `${pad(hour)}:${pad(minute)}:${pad(second)}.${fractionalPart}`
2148
- : `${pad(hour)}:${pad(minute)}:${pad(second)}`;
2149
- return {
2150
- date,
2151
- datePart: normalizedDatePart,
2152
- timePart: normalizedTimePart,
2153
- };
2154
- }
2155
- function buildIsoOffset(timezoneOffsetMinutes) {
2156
- const totalMinutes = -timezoneOffsetMinutes;
2157
- const sign = totalMinutes >= 0 ? '+' : '-';
2158
- const absoluteMinutes = Math.abs(totalMinutes);
2159
- const hours = Math.floor(absoluteMinutes / 60);
2160
- const minutes = absoluteMinutes % 60;
2161
- return `${sign}${pad(hours)}:${pad(minutes)}`;
2162
- }
2163
- function pad(value) {
2164
- return String(value).padStart(2, '0');
2165
- }
2166
-
2167
- function prepareSubmitPayload(rawValue, fieldMetadata, options = {}) {
2168
- const normalized = normalizeSubmitPayload(rawValue);
2169
- if (!normalized || typeof normalized !== 'object' || Array.isArray(normalized)) {
2170
- return normalized;
2171
- }
2172
- const dirtyFields = new Set(options.dirtyFields || []);
2173
- return filterRecordForSubmit(normalized, fieldMetadata || [], dirtyFields);
2174
- }
2175
- function shouldOmitEmptyOptionalField(field, value, dirtyFields, scopePath) {
2176
- if (isFieldDirty(field.name, dirtyFields, scopePath) || isRequiredField(field)) {
2177
- return false;
2178
- }
2179
- return value === null || value === undefined || value === '';
2180
- }
2181
- function isRequiredField(field) {
2182
- const validators = field.validators;
2183
- return field.required === true || validators?.required === true;
2184
- }
2185
- function shouldOmitFieldFromSubmit(field, dirtyFields = new Set(), scopePath) {
2186
- const policy = normalizeSubmitPolicy(field.submitPolicy);
2187
- if (policy) {
2188
- return shouldOmitByPolicy(policy, field.name, dirtyFields, scopePath);
2189
- }
2190
- return field.source === 'local' || field.transient === true;
2191
- }
2192
- function normalizeSubmitPolicy(policy) {
2193
- if (policy === 'include' || policy === 'omit' || policy === 'includeWhenDirty') {
2194
- return policy;
2195
- }
2196
- // Defensive runtime migration for JSON/LLM/configs that may use the old
2197
- // wording. The persisted/public contract remains `omit`.
2198
- if (policy === 'never') {
2199
- return 'omit';
2200
- }
2201
- return undefined;
2202
- }
2203
- function shouldOmitByPolicy(policy, fieldName, dirtyFields, scopePath) {
2204
- switch (policy) {
2205
- case 'include':
2206
- return false;
2207
- case 'omit':
2208
- return true;
2209
- case 'includeWhenDirty':
2210
- return !isFieldDirty(fieldName, dirtyFields, scopePath);
2211
- default:
2212
- return false;
2213
- }
2214
- }
2215
- function filterRecordForSubmit(value, fields, dirtyFields, scopePath) {
2216
- const payload = { ...value };
2217
- for (const field of fields) {
2218
- if (shouldOmitFieldFromSubmit(field, dirtyFields, scopePath)) {
2219
- delete payload[field.name];
2220
- continue;
2221
- }
2222
- const fieldValue = payload[field.name];
2223
- const fieldPath = buildScopedFieldPath(field.name, scopePath);
2224
- payload[field.name] = normalizeFieldValueForSubmit(field, fieldValue, dirtyFields, fieldPath);
2225
- if (shouldOmitEmptyOptionalField(field, payload[field.name], dirtyFields, scopePath)) {
2226
- delete payload[field.name];
2227
- }
2228
- }
2229
- return payload;
2230
- }
2231
- function normalizeFieldValueForSubmit(field, value, dirtyFields, fieldPath) {
2232
- const normalizedDateValue = normalizeDateOnlyFieldValueForSubmit(field, value);
2233
- const normalizedEntityLookupValue = normalizeEntityLookupValueForSubmit(field, normalizedDateValue);
2234
- return filterNestedArrayForSubmit(field, normalizedEntityLookupValue, dirtyFields, fieldPath);
2235
- }
2236
- /**
2237
- * Projects date-only controls into the ISO-8601 representation required by
2238
- * OpenAPI `format: date` / Java `LocalDate` contracts. A date field may hold
2239
- * a native Date (calendar selection) or its locale display value (manual
2240
- * masked input); neither presentation value should leak into the request.
2241
- */
2242
- function normalizeDateOnlyFieldValueForSubmit(field, value) {
2243
- if (!isDateOnlyField(field) || value === null || value === undefined || value === '') {
2244
- return value;
2245
- }
2246
- if (value instanceof Date) {
2247
- return isValidDate(value) ? formatLocalIsoDate(value) : value;
2248
- }
2249
- if (typeof value !== 'string') {
2250
- return value;
2251
- }
2252
- const trimmed = value.trim();
2253
- if (isIsoDate(trimmed)) {
2254
- return trimmed;
2255
- }
2256
- const parsed = parseDayFirstDate(trimmed, field);
2257
- return parsed ? formatLocalIsoDate(parsed) : value;
2258
- }
2259
- function isDateOnlyField(field) {
2260
- const dataType = String(field.dataType ?? '').trim().toLowerCase();
2261
- if (dataType === 'date') {
2262
- return true;
2263
- }
2264
- const controlType = String(field.controlType ?? '').trim().toLowerCase();
2265
- return controlType === 'date' || controlType === 'datepicker' || controlType === 'date_picker';
2266
- }
2267
- function isIsoDate(value) {
2268
- return /^\d{4}-\d{2}-\d{2}$/.test(value);
2269
- }
2270
- function parseDayFirstDate(value, field) {
2271
- const displayFormat = String(field.displayFormat ?? field.mask ?? '').toLowerCase();
2272
- if (!displayFormat.includes('dd') || !displayFormat.includes('mm') || !displayFormat.includes('yyyy')) {
2273
- return null;
2274
- }
2275
- const match = /^(\d{1,2})\/(\d{1,2})\/(\d{4})$/.exec(value);
2276
- if (!match) {
2277
- return null;
2278
- }
2279
- const day = Number(match[1]);
2280
- const month = Number(match[2]);
2281
- const year = Number(match[3]);
2282
- const parsed = new Date(year, month - 1, day);
2283
- return isValidDate(parsed) &&
2284
- parsed.getFullYear() === year &&
2285
- parsed.getMonth() === month - 1 &&
2286
- parsed.getDate() === day
2287
- ? parsed
2288
- : null;
2289
- }
2290
- function isValidDate(value) {
2291
- return !Number.isNaN(value.getTime());
2292
- }
2293
- function formatLocalIsoDate(value) {
2294
- const year = value.getFullYear();
2295
- const month = String(value.getMonth() + 1).padStart(2, '0');
2296
- const day = String(value.getDate()).padStart(2, '0');
2297
- return `${year}-${month}-${day}`;
2298
- }
2299
- function normalizeEntityLookupValueForSubmit(field, value) {
2300
- if (!isEntityLookupField(field)) {
2301
- return value;
2302
- }
2303
- return serializeEntityLookupValueForPayload(value, {
2304
- payloadMode: field.payloadMode,
2305
- multiple: field.multiple === true,
2306
- entityType: field.optionSource?.entityKey?.trim(),
2307
- });
2308
- }
2309
- function filterNestedArrayForSubmit(field, value, dirtyFields, fieldPath) {
2310
- const itemFields = field.array?.itemSchema?.fields;
2311
- if (!Array.isArray(value) || !itemFields?.length) {
2312
- return value;
2313
- }
2314
- return value.map((item, index) => {
2315
- if (!item || typeof item !== 'object' || Array.isArray(item)) {
2316
- return item;
2317
- }
2318
- return filterRecordForSubmit(item, itemFields, dirtyFields, `${fieldPath}.${index}`);
2319
- });
2320
- }
2321
- function isFieldDirty(fieldName, dirtyFields, scopePath) {
2322
- if (dirtyFields.has(fieldName)) {
2323
- return true;
2324
- }
2325
- if (!scopePath) {
2326
- return false;
2327
- }
2328
- return (dirtyFields.has(scopePath) ||
2329
- dirtyFields.has(buildScopedFieldPath(fieldName, scopePath)) ||
2330
- dirtyFields.has(buildBracketScopedFieldPath(fieldName, scopePath)));
2331
- }
2332
- function buildScopedFieldPath(fieldName, scopePath) {
2333
- return scopePath ? `${scopePath}.${fieldName}` : fieldName;
2334
- }
2335
- function buildBracketScopedFieldPath(fieldName, scopePath) {
2336
- const bracketPath = scopePath.replace(/\.(\d+)(?=\.|$)/g, '[$1]');
2337
- return `${bracketPath}.${fieldName}`;
2338
- }
2339
- function isEntityLookupField(field) {
2340
- return (field.controlType === 'entityLookup' ||
2341
- field.controlType === 'inlineEntityLookup');
2342
- }
2343
-
2344
2380
  const SECTION_HEADER_INITIALS_MIN = 1;
2345
2381
  const SECTION_HEADER_INITIALS_MAX = 4;
2346
2382
  const SECTION_HEADER_INITIALS_DEFAULT = 2;
@@ -11568,6 +11604,10 @@ class PraxisDynamicForm {
11568
11604
  * 'filter' usa o schema do DTO de filtro (via /schemas/filtered no POST /filter request)
11569
11605
  */
11570
11606
  schemaSource = 'resource';
11607
+ /** Canonical workflow/action identifier when bound to a command surface. */
11608
+ actionId;
11609
+ /** Canonical backend operationId when bound to a command/surface endpoint. */
11610
+ operationId;
11571
11611
  /** Canonical schema URL published by the backend surface catalog. */
11572
11612
  schemaUrl;
11573
11613
  /** Canonical read URL published by backend view/read-projection surfaces. */
@@ -14007,16 +14047,21 @@ class PraxisDynamicForm {
14007
14047
  // Don't re-throw - continue with local config
14008
14048
  }
14009
14049
  }
14050
+ isActionCommandWithoutExplicitReadUrl() {
14051
+ return this.schemaSource === 'action' && !String(this.readUrl || '').trim();
14052
+ }
14010
14053
  loadEntity() {
14011
14054
  this.debugLog('[PDF] loadEntity:start', { id: this.pendingEntityId });
14012
- // CREATE may still carry a resourceId when the form materializes an
14013
- // item-scoped command (approve, deactivate, reactivate, etc.). In that
14014
- // case the id belongs to the command context and must not trigger an
14055
+ // CREATE or an item-scoped action form (schemaSource === 'action' without
14056
+ // an explicit readUrl) may carry a resourceId when the form materializes an
14057
+ // item-scoped command (approve, start, deactivate, reactivate, etc.). In
14058
+ // that case the id belongs to the command context and must not trigger an
14015
14059
  // entity read/hydration cycle. Command defaults are supplied explicitly
14016
14060
  // through initialValue.
14017
- if (this.mode === 'create') {
14061
+ if (this.mode === 'create' || this.isActionCommandWithoutExplicitReadUrl()) {
14018
14062
  this.entityReadFailed = false;
14019
14063
  this.entityHydrationPending = false;
14064
+ this.hydratedEntityId = this.pendingEntityId;
14020
14065
  const normalized = this.getNormalizedInitialValue();
14021
14066
  if (normalized && Object.keys(this.form.controls || {}).length) {
14022
14067
  this.form.patchValue(normalized, { emitEvent: false });
@@ -14307,7 +14352,7 @@ class PraxisDynamicForm {
14307
14352
  return this.http
14308
14353
  .post(resolveReactiveDeterminationHref(definition.capability.href, this.resolveApiOrigin()), requestBody, { headers })
14309
14354
  .pipe(map$1((response) => this.unwrapRestApiResponse(response)));
14310
- }, (event) => this.handleReactiveDeterminationExecutionEvent(event)));
14355
+ }, (event) => this.handleReactiveDeterminationExecutionEvent(event), undefined, this.config?.fieldMetadata));
14311
14356
  connection.add(this.reactiveDeterminationRuntime.observePending(this.form, (pending) => this.setReactiveDeterminationPending(pending)));
14312
14357
  this.reactiveDeterminationSubscription = connection;
14313
14358
  });
@@ -14682,7 +14727,7 @@ class PraxisDynamicForm {
14682
14727
  * canonical and later seed changes must not reset remote fields or unsaved edits.
14683
14728
  */
14684
14729
  usesInitialValueAsAuthoritativeSnapshot() {
14685
- if (this.mode === 'create') {
14730
+ if (this.mode === 'create' || this.isActionCommandWithoutExplicitReadUrl()) {
14686
14731
  return true;
14687
14732
  }
14688
14733
  return !String(this.readUrl || '').trim() && !String(this.resourcePath || '').trim();
@@ -21903,6 +21948,11 @@ class PraxisDynamicForm {
21903
21948
  if (this.isDestroyed)
21904
21949
  throw new PraxisDynamicFormDestroyedError();
21905
21950
  const defs = this.schemaNormalizer.normalizeSchema(entry.schema);
21951
+ if ((!Array.isArray(defs) || defs.length === 0) &&
21952
+ this.schemaSource === 'action' &&
21953
+ String(this.resourcePath || '').trim()) {
21954
+ return await loadLegacySchema(new Error('Action request schema returned no fields; falling back to resource schema.'));
21955
+ }
21906
21956
  // Parse backend-owned root x-ui runtime contracts. They remain transient
21907
21957
  // and are never copied into the persisted/authorable FormConfig.
21908
21958
  try {
@@ -22136,7 +22186,7 @@ class PraxisDynamicForm {
22136
22186
  }
22137
22187
  }
22138
22188
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisDynamicForm, deps: [{ token: i1.GenericCrudService }, { token: i2.HttpClient }, { token: i1$3.FormBuilder }, { token: i0.ChangeDetectorRef }, { token: FormLayoutService }, { token: FormContextService }, { token: FormRulesService }, { token: i7.SettingsPanelService }, { token: i2$1.MatDialog }, { token: ASYNC_CONFIG_STORAGE }, { token: CONNECTION_STORAGE }, { token: i1.DynamicFormService }, { token: i9.MatSnackBar }, { token: CanvasStateService }, { token: DynamicFormLayoutService }, { token: ReactiveDeterminationRuntimeService }, { token: i1.ErrorMessageService }, { token: i1.SchemaNormalizerService }, { token: i1.ComponentMetadataRegistry }, { token: i1.GlobalConfigService }, { token: i1.ComponentKeyService }, { token: i1.LoadingOrchestrator }, { token: i0.NgZone }, { token: API_URL }, { token: PRAXIS_LOADING_RENDERER, optional: true }, { token: i13.Router, optional: true }, { token: i13.ActivatedRoute, optional: true }, { token: i1.FormHooksRegistry, optional: true }, { token: FORM_HOOKS_PRESETS, optional: true }, { token: i1.LoggerService, optional: true }, { token: i1.EnterpriseRuntimeContextService, optional: true }], target: i0.ɵɵFactoryTarget.Component });
22139
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: PraxisDynamicForm, isStandalone: true, selector: "praxis-dynamic-form", inputs: { resourcePath: "resourcePath", resourceId: "resourceId", initialValue: "initialValue", emptyState: "emptyState", editorialContext: "editorialContext", mode: "mode", config: "config", actions: "actions", schemaSource: "schemaSource", schemaUrl: "schemaUrl", readUrl: "readUrl", submitUrl: "submitUrl", submitMethod: "submitMethod", submitIdempotencyKey: "submitIdempotencyKey", submitCorrelationId: "submitCorrelationId", submitResourceVersion: "submitResourceVersion", submitResourceVersionTargetResourceKey: "submitResourceVersionTargetResourceKey", submitResourceVersionTargetIdField: "submitResourceVersionTargetIdField", responseSchemaUrl: "responseSchemaUrl", apiEndpointKey: "apiEndpointKey", apiUrlEntry: "apiUrlEntry", enableCustomization: "enableCustomization", showAiAssistant: "showAiAssistant", formId: "formId", componentInstanceId: "componentInstanceId", configPersistenceStrategy: "configPersistenceStrategy", layout: "layout", layoutMode: "layoutMode", formLayout: "formLayout", generatedLayoutPreset: "generatedLayoutPreset", layoutPolicy: "layoutPolicy", backConfig: "backConfig", hooks: "hooks", removeEmptyContainersOnSave: "removeEmptyContainersOnSave", reactiveValidation: "reactiveValidation", reactiveValidationDebounceMs: "reactiveValidationDebounceMs", notifyIfOutdated: "notifyIfOutdated", snoozeMs: "snoozeMs", autoOpenSettingsOnOutdated: "autoOpenSettingsOnOutdated", readonlyModeGlobal: "readonlyModeGlobal", disabledModeGlobal: "disabledModeGlobal", presentationModeGlobal: "presentationModeGlobal", presentation: "presentation", presentationPreset: "presentationPreset", sectionDefaultAppearance: "sectionDefaultAppearance", sectionDivider: "sectionDivider", visibleGlobal: "visibleGlobal", fieldIconPolicy: "fieldIconPolicy", domainRules: "domainRules", customEndpoints: "customEndpoints" }, outputs: { formSubmit: "formSubmit", formCancel: "formCancel", formReset: "formReset", configChange: "configChange", configPatchChange: "configPatchChange", formReady: "formReady", valueChange: "valueChange", payloadPreviewChange: "payloadPreviewChange", syncCompleted: "syncCompleted", initializationError: "initializationError", loadingStateChange: "loadingStateChange", enableCustomizationChange: "enableCustomizationChange", customAction: "customAction", actionConfirmation: "actionConfirmation", schemaStatusChange: "schemaStatusChange", fieldRenderError: "fieldRenderError", ruleDiagnosticsChange: "ruleDiagnosticsChange", reactiveDeterminationExecuted: "reactiveDeterminationExecuted", reactiveDeterminationPendingChange: "reactiveDeterminationPendingChange", tabChange: "tabChange", tabSelected: "tabSelected" }, providers: [
22189
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: PraxisDynamicForm, isStandalone: true, selector: "praxis-dynamic-form", inputs: { resourcePath: "resourcePath", resourceId: "resourceId", initialValue: "initialValue", emptyState: "emptyState", editorialContext: "editorialContext", mode: "mode", config: "config", actions: "actions", schemaSource: "schemaSource", actionId: "actionId", operationId: "operationId", schemaUrl: "schemaUrl", readUrl: "readUrl", submitUrl: "submitUrl", submitMethod: "submitMethod", submitIdempotencyKey: "submitIdempotencyKey", submitCorrelationId: "submitCorrelationId", submitResourceVersion: "submitResourceVersion", submitResourceVersionTargetResourceKey: "submitResourceVersionTargetResourceKey", submitResourceVersionTargetIdField: "submitResourceVersionTargetIdField", responseSchemaUrl: "responseSchemaUrl", apiEndpointKey: "apiEndpointKey", apiUrlEntry: "apiUrlEntry", enableCustomization: "enableCustomization", showAiAssistant: "showAiAssistant", formId: "formId", componentInstanceId: "componentInstanceId", configPersistenceStrategy: "configPersistenceStrategy", layout: "layout", layoutMode: "layoutMode", formLayout: "formLayout", generatedLayoutPreset: "generatedLayoutPreset", layoutPolicy: "layoutPolicy", backConfig: "backConfig", hooks: "hooks", removeEmptyContainersOnSave: "removeEmptyContainersOnSave", reactiveValidation: "reactiveValidation", reactiveValidationDebounceMs: "reactiveValidationDebounceMs", notifyIfOutdated: "notifyIfOutdated", snoozeMs: "snoozeMs", autoOpenSettingsOnOutdated: "autoOpenSettingsOnOutdated", readonlyModeGlobal: "readonlyModeGlobal", disabledModeGlobal: "disabledModeGlobal", presentationModeGlobal: "presentationModeGlobal", presentation: "presentation", presentationPreset: "presentationPreset", sectionDefaultAppearance: "sectionDefaultAppearance", sectionDivider: "sectionDivider", visibleGlobal: "visibleGlobal", fieldIconPolicy: "fieldIconPolicy", domainRules: "domainRules", customEndpoints: "customEndpoints" }, outputs: { formSubmit: "formSubmit", formCancel: "formCancel", formReset: "formReset", configChange: "configChange", configPatchChange: "configPatchChange", formReady: "formReady", valueChange: "valueChange", payloadPreviewChange: "payloadPreviewChange", syncCompleted: "syncCompleted", initializationError: "initializationError", loadingStateChange: "loadingStateChange", enableCustomizationChange: "enableCustomizationChange", customAction: "customAction", actionConfirmation: "actionConfirmation", schemaStatusChange: "schemaStatusChange", fieldRenderError: "fieldRenderError", ruleDiagnosticsChange: "ruleDiagnosticsChange", reactiveDeterminationExecuted: "reactiveDeterminationExecuted", reactiveDeterminationPendingChange: "reactiveDeterminationPendingChange", tabChange: "tabChange", tabSelected: "tabSelected" }, providers: [
22140
22190
  providePraxisI18nConfig(PRAXIS_DYNAMIC_FORM_I18N_CONFIG),
22141
22191
  GenericCrudService,
22142
22192
  FormContextService,
@@ -22214,6 +22264,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
22214
22264
  type: Input
22215
22265
  }], schemaSource: [{
22216
22266
  type: Input
22267
+ }], actionId: [{
22268
+ type: Input
22269
+ }], operationId: [{
22270
+ type: Input
22217
22271
  }], schemaUrl: [{
22218
22272
  type: Input
22219
22273
  }], readUrl: [{
@@ -36761,7 +36815,7 @@ class Ergadm00034CompactPresentationExampleComponent {
36761
36815
  corporatePresentationConfig = buildCorporatePresentationFormatGalleryConfig(this.dynamicLayout);
36762
36816
  corporatePresentationInitialValue = this.corporatePresentationExample.initialValue;
36763
36817
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: Ergadm00034CompactPresentationExampleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
36764
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: Ergadm00034CompactPresentationExampleComponent, isStandalone: true, selector: "praxis-ergadm00034-compact-presentation-example", ngImport: i0, template: "<mat-card class=\"legacy-presentation-card\" data-testid=\"ergadm00034-compact-fixture\">\n <div class=\"legacy-presentation-header\">\n <div>\n <p class=\"examples-eyebrow\">Exemplo visual da lib</p>\n <h2>{{ legacyFrequencyExample.title }}</h2>\n <p>\n Fixture visual representativo de <code>{{ legacyFrequencyExample.resourcePath }}</code>:\n cinco registros densos e detalhe gerado por <code>x-ui.group</code>, <code>order</code>\n e <code>width</code>, sem declarar <code>FormConfig.sections</code> no host.\n </p>\n </div>\n <div class=\"legacy-presentation-badge\">\n <mat-icon aria-hidden=\"true\">view_compact</mat-icon>\n <span>compactPresentation</span>\n </div>\n </div>\n\n <div class=\"legacy-workbench\">\n <section class=\"legacy-records-panel\" aria-labelledby=\"legacy-records-title\">\n <div class=\"legacy-panel-heading\">\n <div>\n <h3 id=\"legacy-records-title\">C\u00F3digos de frequ\u00EAncia</h3>\n <p>5 registros carregados</p>\n </div>\n <span class=\"legacy-count-chip\">fixture local</span>\n </div>\n\n <div class=\"legacy-table-wrap\">\n <table class=\"legacy-record-table\" aria-label=\"C\u00F3digos de frequ\u00EAncia\">\n <thead>\n <tr>\n <th scope=\"col\">Tipo</th>\n <th scope=\"col\">C\u00F3digo</th>\n <th scope=\"col\">Nome</th>\n <th scope=\"col\">Preench.</th>\n <th scope=\"col\">Marcador</th>\n </tr>\n </thead>\n <tbody>\n @for (row of legacyFrequencyRows; track row.codigo) {\n <tr [class.is-selected]=\"row.selected\">\n <td>{{ row.tipo }}</td>\n <td><strong>{{ row.codigo }}</strong></td>\n <td>{{ row.nome }}</td>\n <td>{{ row.preenchimento }}</td>\n <td>{{ row.marcador }}</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n </section>\n\n <section class=\"legacy-detail-panel\" aria-labelledby=\"legacy-detail-title\">\n <div class=\"legacy-detail-toolbar\">\n <div>\n <p class=\"legacy-detail-kicker\">Registro selecionado</p>\n <h3 id=\"legacy-detail-title\">AFA - Afastamento abonado</h3>\n </div>\n <div class=\"legacy-detail-actions\" aria-label=\"A\u00E7\u00F5es do registro\">\n <button type=\"button\" aria-label=\"Novo c\u00F3digo de frequ\u00EAncia\">\n <mat-icon aria-hidden=\"true\">add</mat-icon>\n </button>\n <button type=\"button\" aria-label=\"Editar c\u00F3digo de frequ\u00EAncia\">\n <mat-icon aria-hidden=\"true\">edit</mat-icon>\n </button>\n </div>\n </div>\n\n <div class=\"legacy-detail-tabs\" aria-label=\"Abas do detalhe\">\n <button type=\"button\" class=\"is-active\">\n <mat-icon aria-hidden=\"true\">fact_check</mat-icon>\n <span>Detalhes</span>\n </button>\n <button type=\"button\">\n <mat-icon aria-hidden=\"true\">gavel</mat-icon>\n <span>Documentos legais</span>\n </button>\n </div>\n\n <praxis-dynamic-form\n class=\"presentation-mode pres-label-left pres-density-compact legacy-frequency-form\"\n data-testid=\"ergadm00034-detail-form\"\n formId=\"legacy-frequency-compact-presentation-demo\"\n [config]=\"legacyFrequencyPresentationConfig\"\n [initialValue]=\"legacyFrequencyInitialValue\"\n mode=\"view\"\n [presentationModeGlobal]=\"true\"\n [enableCustomization]=\"false\"\n [showAiAssistant]=\"false\"\n ></praxis-dynamic-form>\n </section>\n </div>\n\n <section class=\"corporate-format-gallery\" data-testid=\"corporate-format-gallery\">\n <div class=\"corporate-gallery-heading\">\n <div>\n <p class=\"examples-eyebrow\">Valida\u00E7\u00E3o de apresenta\u00E7\u00E3o</p>\n <h2>{{ corporatePresentationExample.title }}</h2>\n <p>\n Fixture de <code>{{ corporatePresentationExample.resourcePath }}</code> para validar\n datas, moedas, percentuais, quantidades, documentos, listas e status em telas densas.\n </p>\n </div>\n <div class=\"corporate-kpi-strip\" aria-label=\"Resumo financeiro\">\n <span>\n <strong>R$ 1,38 mi</strong>\n <small>valor bruto</small>\n </span>\n <span>\n <strong>18,45%</strong>\n <small>margem</small>\n </span>\n <span>\n <strong>42</strong>\n <small>itens</small>\n </span>\n </div>\n </div>\n\n <praxis-dynamic-form\n class=\"presentation-mode pres-label-left pres-density-compact corporate-format-form\"\n data-testid=\"corporate-format-detail-form\"\n formId=\"corporate-format-gallery-demo\"\n [config]=\"corporatePresentationConfig\"\n [initialValue]=\"corporatePresentationInitialValue\"\n mode=\"view\"\n [presentationModeGlobal]=\"true\"\n [enableCustomization]=\"false\"\n [showAiAssistant]=\"false\"\n ></praxis-dynamic-form>\n </section>\n</mat-card>\n", styles: [":host{--pdx-ergadm-bg: var(--mat-sys-surface, var(--md-sys-color-surface, #ffffff));--pdx-ergadm-surface-strong: color-mix( in srgb, var(--mat-sys-surface-container-high, var(--md-sys-color-surface-container-high, #eef3f1)) 90%, var(--pdx-ergadm-bg) );--pdx-ergadm-border: color-mix( in srgb, var(--mat-sys-outline-variant, var(--md-sys-color-outline-variant, #c6d0cb)) 76%, transparent );--pdx-ergadm-text: var(--mat-sys-on-surface, var(--md-sys-color-on-surface, #17221d));--pdx-ergadm-text-muted: var( --mat-sys-on-surface-variant, var(--md-sys-color-on-surface-variant, #53625c) );--pdx-ergadm-primary: var(--mat-sys-primary, var(--md-sys-color-primary, #0f766e));--pdx-ergadm-primary-strong: color-mix(in srgb, var(--pdx-ergadm-primary) 82%, black);--pdx-ergadm-primary-soft: color-mix(in srgb, var(--pdx-ergadm-primary) 14%, transparent);--pdx-ergadm-chip-bg: color-mix( in srgb, var(--mat-sys-primary-container, var(--md-sys-color-primary-container, #dcefeb)) 74%, var(--pdx-ergadm-bg) );--pdx-ergadm-chip-text: var( --mat-sys-on-primary-container, var(--md-sys-color-on-primary-container, #123932) );--pdx-ergadm-shadow-soft: 0 18px 36px rgba(15, 23, 42, .06);display:block;min-width:0;color:var(--pdx-ergadm-text)}.legacy-presentation-card{padding:22px;border-radius:20px;border:1px solid var(--pdx-ergadm-border);background:linear-gradient(180deg,color-mix(in srgb,var(--pdx-ergadm-surface-strong) 86%,var(--pdx-ergadm-bg)) 0%,var(--pdx-ergadm-bg) 100%);box-shadow:var(--pdx-ergadm-shadow-soft)}.legacy-presentation-header{display:flex;align-items:flex-start;justify-content:space-between;gap:18px;margin-bottom:14px}.examples-eyebrow{margin:0;text-transform:uppercase;letter-spacing:.18em;font-size:.76rem;font-weight:800;color:color-mix(in srgb,var(--pdx-ergadm-primary) 84%,var(--pdx-ergadm-text))}.legacy-presentation-header h2{margin:6px 0 8px;font-size:clamp(1.18rem,1.6vw,1.48rem);line-height:1.14}.legacy-presentation-header p{margin:0;max-width:76ch;color:var(--pdx-ergadm-text-muted);line-height:1.55}.legacy-presentation-badge{display:inline-flex;align-items:center;gap:8px;flex:0 0 auto;padding:8px 12px;border-radius:999px;border:1px solid color-mix(in srgb,var(--pdx-ergadm-primary) 18%,transparent);background:var(--pdx-ergadm-chip-bg);color:var(--pdx-ergadm-chip-text);font-size:.82rem;font-weight:800}.legacy-workbench{display:grid;grid-template-columns:minmax(360px,.44fr) minmax(0,1fr);gap:14px;align-items:start}.legacy-records-panel,.legacy-detail-panel{min-width:0;border:1px solid var(--pdx-ergadm-border);border-radius:14px;background:color-mix(in srgb,var(--pdx-ergadm-bg) 88%,var(--pdx-ergadm-surface-strong))}.legacy-records-panel{overflow:hidden}.legacy-detail-panel{padding:12px}.legacy-panel-heading,.legacy-detail-toolbar{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.legacy-panel-heading{padding:12px 14px 10px;border-bottom:1px solid var(--pdx-ergadm-border)}.legacy-panel-heading h3,.legacy-detail-toolbar h3{margin:0;font-size:.98rem;line-height:1.25}.legacy-panel-heading p,.legacy-detail-kicker{margin:3px 0 0;color:var(--pdx-ergadm-text-muted);font-size:.76rem;line-height:1.35}.legacy-count-chip{flex:0 0 auto;padding:5px 8px;border-radius:999px;background:var(--pdx-ergadm-primary-soft);color:var(--pdx-ergadm-primary-strong);font-size:.68rem;font-weight:800;text-transform:uppercase}.legacy-table-wrap{overflow-x:auto}.legacy-record-table{width:100%;min-width:500px;border-collapse:collapse;font-size:.78rem;line-height:1.25}.legacy-record-table th,.legacy-record-table td{padding:8px 10px;text-align:left;white-space:nowrap;border-bottom:1px solid color-mix(in srgb,var(--pdx-ergadm-border) 78%,transparent)}.legacy-record-table th{color:var(--pdx-ergadm-text-muted);font-size:.66rem;font-weight:800;text-transform:uppercase}.legacy-record-table td:nth-child(3){max-width:190px;overflow:hidden;text-overflow:ellipsis}.legacy-record-table tr:last-child td{border-bottom:0}.legacy-record-table tr.is-selected td{background:color-mix(in srgb,var(--pdx-ergadm-primary) 11%,transparent)}.legacy-detail-actions{display:inline-flex;gap:6px;flex:0 0 auto}.legacy-detail-actions button{display:inline-grid;place-items:center;width:32px;height:32px;border:1px solid var(--pdx-ergadm-border);border-radius:8px;background:var(--pdx-ergadm-bg);color:var(--pdx-ergadm-primary-strong);cursor:default}.legacy-detail-actions mat-icon{width:18px;height:18px;font-size:18px}.legacy-detail-tabs{display:flex;gap:6px;margin:12px 0;padding-bottom:8px;border-bottom:1px solid var(--pdx-ergadm-border);overflow-x:auto}.legacy-detail-tabs button{display:inline-flex;align-items:center;gap:6px;min-height:30px;padding:5px 9px;border:1px solid transparent;border-radius:999px;background:transparent;color:var(--pdx-ergadm-text-muted);font:inherit;font-size:.78rem;font-weight:700;white-space:nowrap}.legacy-detail-tabs button.is-active{border-color:color-mix(in srgb,var(--pdx-ergadm-primary) 18%,transparent);background:var(--pdx-ergadm-primary-soft);color:var(--pdx-ergadm-primary-strong)}.legacy-detail-tabs mat-icon{width:16px;height:16px;font-size:16px}.legacy-frequency-form{--pdx-presentation-label-width: 116px;--pdx-presentation-label-size: .7rem;--pdx-presentation-value-size: .9rem;--pdx-presentation-flag-height: 20px;--pdx-presentation-flag-padding: 0 7px;display:block}.corporate-format-gallery{margin-top:18px;padding-top:18px;border-top:1px solid var(--pdx-ergadm-border)}.corporate-gallery-heading{display:grid;grid-template-columns:minmax(0,1fr) minmax(260px,.34fr);gap:16px;align-items:start;margin-bottom:12px}.corporate-gallery-heading h2{margin:6px 0 8px;font-size:clamp(1.08rem,1.35vw,1.32rem);line-height:1.16}.corporate-gallery-heading p{margin:0;max-width:82ch;color:var(--pdx-ergadm-text-muted);line-height:1.55}.corporate-kpi-strip{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}.corporate-kpi-strip span{min-width:0;padding:10px;border:1px solid var(--pdx-ergadm-border);border-radius:12px;background:color-mix(in srgb,var(--pdx-ergadm-bg) 86%,var(--pdx-ergadm-primary-soft))}.corporate-kpi-strip strong,.corporate-kpi-strip small{display:block;min-width:0;overflow-wrap:anywhere}.corporate-kpi-strip strong{color:var(--pdx-ergadm-primary-strong);font-size:.96rem;line-height:1.2}.corporate-kpi-strip small{margin-top:3px;color:var(--pdx-ergadm-text-muted);font-size:.68rem;font-weight:700;text-transform:uppercase}.corporate-format-form{--pdx-presentation-label-width: 132px;--pdx-presentation-label-size: .7rem;--pdx-presentation-value-size: .9rem;display:block;padding:12px;border:1px solid var(--pdx-ergadm-border);border-radius:14px;background:color-mix(in srgb,var(--pdx-ergadm-bg) 90%,var(--pdx-ergadm-surface-strong))}@media(max-width:960px){.legacy-workbench,.corporate-gallery-heading{grid-template-columns:1fr}}@media(max-width:720px){.legacy-presentation-card{padding:18px;border-radius:20px}.legacy-presentation-header{display:grid}.legacy-presentation-badge{width:fit-content}.legacy-records-panel,.legacy-detail-panel{border-radius:12px}.legacy-panel-heading,.legacy-detail-toolbar{display:grid}.legacy-record-table{min-width:460px}.legacy-frequency-form{--pdx-presentation-label-width: 104px}.corporate-kpi-strip{grid-template-columns:1fr}.corporate-format-form{--pdx-presentation-label-width: 104px;padding:10px}}\n"], dependencies: [{ kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i7$1.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: PraxisDynamicForm, selector: "praxis-dynamic-form", inputs: ["resourcePath", "resourceId", "initialValue", "emptyState", "editorialContext", "mode", "config", "actions", "schemaSource", "schemaUrl", "readUrl", "submitUrl", "submitMethod", "submitIdempotencyKey", "submitCorrelationId", "submitResourceVersion", "submitResourceVersionTargetResourceKey", "submitResourceVersionTargetIdField", "responseSchemaUrl", "apiEndpointKey", "apiUrlEntry", "enableCustomization", "showAiAssistant", "formId", "componentInstanceId", "configPersistenceStrategy", "layout", "layoutMode", "formLayout", "generatedLayoutPreset", "layoutPolicy", "backConfig", "hooks", "removeEmptyContainersOnSave", "reactiveValidation", "reactiveValidationDebounceMs", "notifyIfOutdated", "snoozeMs", "autoOpenSettingsOnOutdated", "readonlyModeGlobal", "disabledModeGlobal", "presentationModeGlobal", "presentation", "presentationPreset", "sectionDefaultAppearance", "sectionDivider", "visibleGlobal", "fieldIconPolicy", "domainRules", "customEndpoints"], outputs: ["formSubmit", "formCancel", "formReset", "configChange", "configPatchChange", "formReady", "valueChange", "payloadPreviewChange", "syncCompleted", "initializationError", "loadingStateChange", "enableCustomizationChange", "customAction", "actionConfirmation", "schemaStatusChange", "fieldRenderError", "ruleDiagnosticsChange", "reactiveDeterminationExecuted", "reactiveDeterminationPendingChange", "tabChange", "tabSelected"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
36818
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: Ergadm00034CompactPresentationExampleComponent, isStandalone: true, selector: "praxis-ergadm00034-compact-presentation-example", ngImport: i0, template: "<mat-card class=\"legacy-presentation-card\" data-testid=\"ergadm00034-compact-fixture\">\n <div class=\"legacy-presentation-header\">\n <div>\n <p class=\"examples-eyebrow\">Exemplo visual da lib</p>\n <h2>{{ legacyFrequencyExample.title }}</h2>\n <p>\n Fixture visual representativo de <code>{{ legacyFrequencyExample.resourcePath }}</code>:\n cinco registros densos e detalhe gerado por <code>x-ui.group</code>, <code>order</code>\n e <code>width</code>, sem declarar <code>FormConfig.sections</code> no host.\n </p>\n </div>\n <div class=\"legacy-presentation-badge\">\n <mat-icon aria-hidden=\"true\">view_compact</mat-icon>\n <span>compactPresentation</span>\n </div>\n </div>\n\n <div class=\"legacy-workbench\">\n <section class=\"legacy-records-panel\" aria-labelledby=\"legacy-records-title\">\n <div class=\"legacy-panel-heading\">\n <div>\n <h3 id=\"legacy-records-title\">C\u00F3digos de frequ\u00EAncia</h3>\n <p>5 registros carregados</p>\n </div>\n <span class=\"legacy-count-chip\">fixture local</span>\n </div>\n\n <div class=\"legacy-table-wrap\">\n <table class=\"legacy-record-table\" aria-label=\"C\u00F3digos de frequ\u00EAncia\">\n <thead>\n <tr>\n <th scope=\"col\">Tipo</th>\n <th scope=\"col\">C\u00F3digo</th>\n <th scope=\"col\">Nome</th>\n <th scope=\"col\">Preench.</th>\n <th scope=\"col\">Marcador</th>\n </tr>\n </thead>\n <tbody>\n @for (row of legacyFrequencyRows; track row.codigo) {\n <tr [class.is-selected]=\"row.selected\">\n <td>{{ row.tipo }}</td>\n <td><strong>{{ row.codigo }}</strong></td>\n <td>{{ row.nome }}</td>\n <td>{{ row.preenchimento }}</td>\n <td>{{ row.marcador }}</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n </section>\n\n <section class=\"legacy-detail-panel\" aria-labelledby=\"legacy-detail-title\">\n <div class=\"legacy-detail-toolbar\">\n <div>\n <p class=\"legacy-detail-kicker\">Registro selecionado</p>\n <h3 id=\"legacy-detail-title\">AFA - Afastamento abonado</h3>\n </div>\n <div class=\"legacy-detail-actions\" aria-label=\"A\u00E7\u00F5es do registro\">\n <button type=\"button\" aria-label=\"Novo c\u00F3digo de frequ\u00EAncia\">\n <mat-icon aria-hidden=\"true\">add</mat-icon>\n </button>\n <button type=\"button\" aria-label=\"Editar c\u00F3digo de frequ\u00EAncia\">\n <mat-icon aria-hidden=\"true\">edit</mat-icon>\n </button>\n </div>\n </div>\n\n <div class=\"legacy-detail-tabs\" aria-label=\"Abas do detalhe\">\n <button type=\"button\" class=\"is-active\">\n <mat-icon aria-hidden=\"true\">fact_check</mat-icon>\n <span>Detalhes</span>\n </button>\n <button type=\"button\">\n <mat-icon aria-hidden=\"true\">gavel</mat-icon>\n <span>Documentos legais</span>\n </button>\n </div>\n\n <praxis-dynamic-form\n class=\"presentation-mode pres-label-left pres-density-compact legacy-frequency-form\"\n data-testid=\"ergadm00034-detail-form\"\n formId=\"legacy-frequency-compact-presentation-demo\"\n [config]=\"legacyFrequencyPresentationConfig\"\n [initialValue]=\"legacyFrequencyInitialValue\"\n mode=\"view\"\n [presentationModeGlobal]=\"true\"\n [enableCustomization]=\"false\"\n [showAiAssistant]=\"false\"\n ></praxis-dynamic-form>\n </section>\n </div>\n\n <section class=\"corporate-format-gallery\" data-testid=\"corporate-format-gallery\">\n <div class=\"corporate-gallery-heading\">\n <div>\n <p class=\"examples-eyebrow\">Valida\u00E7\u00E3o de apresenta\u00E7\u00E3o</p>\n <h2>{{ corporatePresentationExample.title }}</h2>\n <p>\n Fixture de <code>{{ corporatePresentationExample.resourcePath }}</code> para validar\n datas, moedas, percentuais, quantidades, documentos, listas e status em telas densas.\n </p>\n </div>\n <div class=\"corporate-kpi-strip\" aria-label=\"Resumo financeiro\">\n <span>\n <strong>R$ 1,38 mi</strong>\n <small>valor bruto</small>\n </span>\n <span>\n <strong>18,45%</strong>\n <small>margem</small>\n </span>\n <span>\n <strong>42</strong>\n <small>itens</small>\n </span>\n </div>\n </div>\n\n <praxis-dynamic-form\n class=\"presentation-mode pres-label-left pres-density-compact corporate-format-form\"\n data-testid=\"corporate-format-detail-form\"\n formId=\"corporate-format-gallery-demo\"\n [config]=\"corporatePresentationConfig\"\n [initialValue]=\"corporatePresentationInitialValue\"\n mode=\"view\"\n [presentationModeGlobal]=\"true\"\n [enableCustomization]=\"false\"\n [showAiAssistant]=\"false\"\n ></praxis-dynamic-form>\n </section>\n</mat-card>\n", styles: [":host{--pdx-ergadm-bg: var(--mat-sys-surface, var(--md-sys-color-surface, #ffffff));--pdx-ergadm-surface-strong: color-mix( in srgb, var(--mat-sys-surface-container-high, var(--md-sys-color-surface-container-high, #eef3f1)) 90%, var(--pdx-ergadm-bg) );--pdx-ergadm-border: color-mix( in srgb, var(--mat-sys-outline-variant, var(--md-sys-color-outline-variant, #c6d0cb)) 76%, transparent );--pdx-ergadm-text: var(--mat-sys-on-surface, var(--md-sys-color-on-surface, #17221d));--pdx-ergadm-text-muted: var( --mat-sys-on-surface-variant, var(--md-sys-color-on-surface-variant, #53625c) );--pdx-ergadm-primary: var(--mat-sys-primary, var(--md-sys-color-primary, #0f766e));--pdx-ergadm-primary-strong: color-mix(in srgb, var(--pdx-ergadm-primary) 82%, black);--pdx-ergadm-primary-soft: color-mix(in srgb, var(--pdx-ergadm-primary) 14%, transparent);--pdx-ergadm-chip-bg: color-mix( in srgb, var(--mat-sys-primary-container, var(--md-sys-color-primary-container, #dcefeb)) 74%, var(--pdx-ergadm-bg) );--pdx-ergadm-chip-text: var( --mat-sys-on-primary-container, var(--md-sys-color-on-primary-container, #123932) );--pdx-ergadm-shadow-soft: 0 18px 36px rgba(15, 23, 42, .06);display:block;min-width:0;color:var(--pdx-ergadm-text)}.legacy-presentation-card{padding:22px;border-radius:20px;border:1px solid var(--pdx-ergadm-border);background:linear-gradient(180deg,color-mix(in srgb,var(--pdx-ergadm-surface-strong) 86%,var(--pdx-ergadm-bg)) 0%,var(--pdx-ergadm-bg) 100%);box-shadow:var(--pdx-ergadm-shadow-soft)}.legacy-presentation-header{display:flex;align-items:flex-start;justify-content:space-between;gap:18px;margin-bottom:14px}.examples-eyebrow{margin:0;text-transform:uppercase;letter-spacing:.18em;font-size:.76rem;font-weight:800;color:color-mix(in srgb,var(--pdx-ergadm-primary) 84%,var(--pdx-ergadm-text))}.legacy-presentation-header h2{margin:6px 0 8px;font-size:clamp(1.18rem,1.6vw,1.48rem);line-height:1.14}.legacy-presentation-header p{margin:0;max-width:76ch;color:var(--pdx-ergadm-text-muted);line-height:1.55}.legacy-presentation-badge{display:inline-flex;align-items:center;gap:8px;flex:0 0 auto;padding:8px 12px;border-radius:999px;border:1px solid color-mix(in srgb,var(--pdx-ergadm-primary) 18%,transparent);background:var(--pdx-ergadm-chip-bg);color:var(--pdx-ergadm-chip-text);font-size:.82rem;font-weight:800}.legacy-workbench{display:grid;grid-template-columns:minmax(360px,.44fr) minmax(0,1fr);gap:14px;align-items:start}.legacy-records-panel,.legacy-detail-panel{min-width:0;border:1px solid var(--pdx-ergadm-border);border-radius:14px;background:color-mix(in srgb,var(--pdx-ergadm-bg) 88%,var(--pdx-ergadm-surface-strong))}.legacy-records-panel{overflow:hidden}.legacy-detail-panel{padding:12px}.legacy-panel-heading,.legacy-detail-toolbar{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.legacy-panel-heading{padding:12px 14px 10px;border-bottom:1px solid var(--pdx-ergadm-border)}.legacy-panel-heading h3,.legacy-detail-toolbar h3{margin:0;font-size:.98rem;line-height:1.25}.legacy-panel-heading p,.legacy-detail-kicker{margin:3px 0 0;color:var(--pdx-ergadm-text-muted);font-size:.76rem;line-height:1.35}.legacy-count-chip{flex:0 0 auto;padding:5px 8px;border-radius:999px;background:var(--pdx-ergadm-primary-soft);color:var(--pdx-ergadm-primary-strong);font-size:.68rem;font-weight:800;text-transform:uppercase}.legacy-table-wrap{overflow-x:auto}.legacy-record-table{width:100%;min-width:500px;border-collapse:collapse;font-size:.78rem;line-height:1.25}.legacy-record-table th,.legacy-record-table td{padding:8px 10px;text-align:left;white-space:nowrap;border-bottom:1px solid color-mix(in srgb,var(--pdx-ergadm-border) 78%,transparent)}.legacy-record-table th{color:var(--pdx-ergadm-text-muted);font-size:.66rem;font-weight:800;text-transform:uppercase}.legacy-record-table td:nth-child(3){max-width:190px;overflow:hidden;text-overflow:ellipsis}.legacy-record-table tr:last-child td{border-bottom:0}.legacy-record-table tr.is-selected td{background:color-mix(in srgb,var(--pdx-ergadm-primary) 11%,transparent)}.legacy-detail-actions{display:inline-flex;gap:6px;flex:0 0 auto}.legacy-detail-actions button{display:inline-grid;place-items:center;width:32px;height:32px;border:1px solid var(--pdx-ergadm-border);border-radius:8px;background:var(--pdx-ergadm-bg);color:var(--pdx-ergadm-primary-strong);cursor:default}.legacy-detail-actions mat-icon{width:18px;height:18px;font-size:18px}.legacy-detail-tabs{display:flex;gap:6px;margin:12px 0;padding-bottom:8px;border-bottom:1px solid var(--pdx-ergadm-border);overflow-x:auto}.legacy-detail-tabs button{display:inline-flex;align-items:center;gap:6px;min-height:30px;padding:5px 9px;border:1px solid transparent;border-radius:999px;background:transparent;color:var(--pdx-ergadm-text-muted);font:inherit;font-size:.78rem;font-weight:700;white-space:nowrap}.legacy-detail-tabs button.is-active{border-color:color-mix(in srgb,var(--pdx-ergadm-primary) 18%,transparent);background:var(--pdx-ergadm-primary-soft);color:var(--pdx-ergadm-primary-strong)}.legacy-detail-tabs mat-icon{width:16px;height:16px;font-size:16px}.legacy-frequency-form{--pdx-presentation-label-width: 116px;--pdx-presentation-label-size: .7rem;--pdx-presentation-value-size: .9rem;--pdx-presentation-flag-height: 20px;--pdx-presentation-flag-padding: 0 7px;display:block}.corporate-format-gallery{margin-top:18px;padding-top:18px;border-top:1px solid var(--pdx-ergadm-border)}.corporate-gallery-heading{display:grid;grid-template-columns:minmax(0,1fr) minmax(260px,.34fr);gap:16px;align-items:start;margin-bottom:12px}.corporate-gallery-heading h2{margin:6px 0 8px;font-size:clamp(1.08rem,1.35vw,1.32rem);line-height:1.16}.corporate-gallery-heading p{margin:0;max-width:82ch;color:var(--pdx-ergadm-text-muted);line-height:1.55}.corporate-kpi-strip{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}.corporate-kpi-strip span{min-width:0;padding:10px;border:1px solid var(--pdx-ergadm-border);border-radius:12px;background:color-mix(in srgb,var(--pdx-ergadm-bg) 86%,var(--pdx-ergadm-primary-soft))}.corporate-kpi-strip strong,.corporate-kpi-strip small{display:block;min-width:0;overflow-wrap:anywhere}.corporate-kpi-strip strong{color:var(--pdx-ergadm-primary-strong);font-size:.96rem;line-height:1.2}.corporate-kpi-strip small{margin-top:3px;color:var(--pdx-ergadm-text-muted);font-size:.68rem;font-weight:700;text-transform:uppercase}.corporate-format-form{--pdx-presentation-label-width: 132px;--pdx-presentation-label-size: .7rem;--pdx-presentation-value-size: .9rem;display:block;padding:12px;border:1px solid var(--pdx-ergadm-border);border-radius:14px;background:color-mix(in srgb,var(--pdx-ergadm-bg) 90%,var(--pdx-ergadm-surface-strong))}@media(max-width:960px){.legacy-workbench,.corporate-gallery-heading{grid-template-columns:1fr}}@media(max-width:720px){.legacy-presentation-card{padding:18px;border-radius:20px}.legacy-presentation-header{display:grid}.legacy-presentation-badge{width:fit-content}.legacy-records-panel,.legacy-detail-panel{border-radius:12px}.legacy-panel-heading,.legacy-detail-toolbar{display:grid}.legacy-record-table{min-width:460px}.legacy-frequency-form{--pdx-presentation-label-width: 104px}.corporate-kpi-strip{grid-template-columns:1fr}.corporate-format-form{--pdx-presentation-label-width: 104px;padding:10px}}\n"], dependencies: [{ kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i7$1.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: PraxisDynamicForm, selector: "praxis-dynamic-form", inputs: ["resourcePath", "resourceId", "initialValue", "emptyState", "editorialContext", "mode", "config", "actions", "schemaSource", "actionId", "operationId", "schemaUrl", "readUrl", "submitUrl", "submitMethod", "submitIdempotencyKey", "submitCorrelationId", "submitResourceVersion", "submitResourceVersionTargetResourceKey", "submitResourceVersionTargetIdField", "responseSchemaUrl", "apiEndpointKey", "apiUrlEntry", "enableCustomization", "showAiAssistant", "formId", "componentInstanceId", "configPersistenceStrategy", "layout", "layoutMode", "formLayout", "generatedLayoutPreset", "layoutPolicy", "backConfig", "hooks", "removeEmptyContainersOnSave", "reactiveValidation", "reactiveValidationDebounceMs", "notifyIfOutdated", "snoozeMs", "autoOpenSettingsOnOutdated", "readonlyModeGlobal", "disabledModeGlobal", "presentationModeGlobal", "presentation", "presentationPreset", "sectionDefaultAppearance", "sectionDivider", "visibleGlobal", "fieldIconPolicy", "domainRules", "customEndpoints"], outputs: ["formSubmit", "formCancel", "formReset", "configChange", "configPatchChange", "formReady", "valueChange", "payloadPreviewChange", "syncCompleted", "initializationError", "loadingStateChange", "enableCustomizationChange", "customAction", "actionConfirmation", "schemaStatusChange", "fieldRenderError", "ruleDiagnosticsChange", "reactiveDeterminationExecuted", "reactiveDeterminationPendingChange", "tabChange", "tabSelected"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
36765
36819
  }
36766
36820
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: Ergadm00034CompactPresentationExampleComponent, decorators: [{
36767
36821
  type: Component,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@praxisui/dynamic-form",
3
- "version": "10.0.0-rc.39",
3
+ "version": "10.0.0-rc.40",
4
4
  "description": "Angular dynamic form engine for Praxis UI: metadata-driven forms, hooks, and services integrating @praxisui/* packages.",
5
5
  "peerDependencies": {
6
6
  "@angular/common": "^21.0.0",
@@ -9,13 +9,13 @@
9
9
  "@angular/forms": "^21.0.0",
10
10
  "@angular/material": "^21.0.0",
11
11
  "@angular/router": "^21.0.0",
12
- "@praxisui/ai": "^10.0.0-rc.39",
13
- "@praxisui/dynamic-fields": "^10.0.0-rc.39",
14
- "@praxisui/metadata-editor": "^10.0.0-rc.39",
15
- "@praxisui/rich-content": "^10.0.0-rc.39",
16
- "@praxisui/settings-panel": "^10.0.0-rc.39",
17
- "@praxisui/visual-builder": "^10.0.0-rc.39",
18
- "@praxisui/core": "^10.0.0-rc.39",
12
+ "@praxisui/ai": "^10.0.0-rc.40",
13
+ "@praxisui/dynamic-fields": "^10.0.0-rc.40",
14
+ "@praxisui/metadata-editor": "^10.0.0-rc.40",
15
+ "@praxisui/rich-content": "^10.0.0-rc.40",
16
+ "@praxisui/settings-panel": "^10.0.0-rc.40",
17
+ "@praxisui/visual-builder": "^10.0.0-rc.40",
18
+ "@praxisui/core": "^10.0.0-rc.40",
19
19
  "rxjs": "^7.8.0"
20
20
  },
21
21
  "dependencies": {
@@ -375,7 +375,7 @@ declare class ReactiveDeterminationRuntimeService {
375
375
  waitForStable(form: FormGroup, timeoutMs?: number): Promise<boolean>;
376
376
  observePending(form: FormGroup, observer: (pending: boolean) => void): Subscription;
377
377
  isOwnedTarget(form: FormGroup, control: AbstractControl): boolean;
378
- connect(form: FormGroup, definitions: ReactiveDeterminationDefinition[], executor: ReactiveDeterminationExecutor, onEvent?: (event: ReactiveDeterminationExecutionEvent) => void, operationTimeoutMs?: number): Subscription;
378
+ connect(form: FormGroup, definitions: ReactiveDeterminationDefinition[], executor: ReactiveDeterminationExecutor, onEvent?: (event: ReactiveDeterminationExecutionEvent) => void, operationTimeoutMs?: number, fieldMetadata?: readonly FieldMetadata[]): Subscription;
379
379
  private resolveControls;
380
380
  private waitForUpstreamDeterminations;
381
381
  private claimTargets;
@@ -809,7 +809,11 @@ declare class PraxisDynamicForm implements OnInit, OnChanges, OnDestroy {
809
809
  * 'resource' (padrão) usa o schema do recurso (/{resource}/schemas -> .../all response)
810
810
  * 'filter' usa o schema do DTO de filtro (via /schemas/filtered no POST /filter request)
811
811
  */
812
- schemaSource: 'resource' | 'filter';
812
+ schemaSource: 'resource' | 'filter' | 'action';
813
+ /** Canonical workflow/action identifier when bound to a command surface. */
814
+ actionId?: string | null;
815
+ /** Canonical backend operationId when bound to a command/surface endpoint. */
816
+ operationId?: string | null;
813
817
  /** Canonical schema URL published by the backend surface catalog. */
814
818
  schemaUrl?: string | null;
815
819
  /** Canonical read URL published by backend view/read-projection surfaces. */
@@ -1209,6 +1213,7 @@ declare class PraxisDynamicForm implements OnInit, OnChanges, OnDestroy {
1209
1213
  private reconcileLoadedConfigWithServerSchema;
1210
1214
  private hostConfigHasAuthoredLocalFieldsNotInLocalConfig;
1211
1215
  private syncWithServer;
1216
+ private isActionCommandWithoutExplicitReadUrl;
1212
1217
  private loadEntity;
1213
1218
  private hydrateEntityFromInitialValue;
1214
1219
  private flushEntityHydrationState;
@@ -1633,7 +1638,7 @@ declare class PraxisDynamicForm implements OnInit, OnChanges, OnDestroy {
1633
1638
  private applyPresentationVars;
1634
1639
  private applyPresentationConfig;
1635
1640
  static ɵfac: i0.ɵɵFactoryDeclaration<PraxisDynamicForm, [null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, { optional: true; }, { optional: true; }, { optional: true; }, { optional: true; }, { optional: true; }, { optional: true; }, { optional: true; }]>;
1636
- static ɵcmp: i0.ɵɵComponentDeclaration<PraxisDynamicForm, "praxis-dynamic-form", never, { "resourcePath": { "alias": "resourcePath"; "required": false; }; "resourceId": { "alias": "resourceId"; "required": false; }; "initialValue": { "alias": "initialValue"; "required": false; }; "emptyState": { "alias": "emptyState"; "required": false; }; "editorialContext": { "alias": "editorialContext"; "required": false; }; "mode": { "alias": "mode"; "required": false; }; "config": { "alias": "config"; "required": false; }; "actions": { "alias": "actions"; "required": false; }; "schemaSource": { "alias": "schemaSource"; "required": false; }; "schemaUrl": { "alias": "schemaUrl"; "required": false; }; "readUrl": { "alias": "readUrl"; "required": false; }; "submitUrl": { "alias": "submitUrl"; "required": false; }; "submitMethod": { "alias": "submitMethod"; "required": false; }; "submitIdempotencyKey": { "alias": "submitIdempotencyKey"; "required": false; }; "submitCorrelationId": { "alias": "submitCorrelationId"; "required": false; }; "submitResourceVersion": { "alias": "submitResourceVersion"; "required": false; }; "submitResourceVersionTargetResourceKey": { "alias": "submitResourceVersionTargetResourceKey"; "required": false; }; "submitResourceVersionTargetIdField": { "alias": "submitResourceVersionTargetIdField"; "required": false; }; "responseSchemaUrl": { "alias": "responseSchemaUrl"; "required": false; }; "apiEndpointKey": { "alias": "apiEndpointKey"; "required": false; }; "apiUrlEntry": { "alias": "apiUrlEntry"; "required": false; }; "enableCustomization": { "alias": "enableCustomization"; "required": false; }; "showAiAssistant": { "alias": "showAiAssistant"; "required": false; }; "formId": { "alias": "formId"; "required": false; }; "componentInstanceId": { "alias": "componentInstanceId"; "required": false; }; "configPersistenceStrategy": { "alias": "configPersistenceStrategy"; "required": false; }; "layout": { "alias": "layout"; "required": false; }; "layoutMode": { "alias": "layoutMode"; "required": false; }; "formLayout": { "alias": "formLayout"; "required": false; }; "generatedLayoutPreset": { "alias": "generatedLayoutPreset"; "required": false; }; "layoutPolicy": { "alias": "layoutPolicy"; "required": false; }; "backConfig": { "alias": "backConfig"; "required": false; }; "hooks": { "alias": "hooks"; "required": false; }; "removeEmptyContainersOnSave": { "alias": "removeEmptyContainersOnSave"; "required": false; }; "reactiveValidation": { "alias": "reactiveValidation"; "required": false; }; "reactiveValidationDebounceMs": { "alias": "reactiveValidationDebounceMs"; "required": false; }; "notifyIfOutdated": { "alias": "notifyIfOutdated"; "required": false; }; "snoozeMs": { "alias": "snoozeMs"; "required": false; }; "autoOpenSettingsOnOutdated": { "alias": "autoOpenSettingsOnOutdated"; "required": false; }; "readonlyModeGlobal": { "alias": "readonlyModeGlobal"; "required": false; }; "disabledModeGlobal": { "alias": "disabledModeGlobal"; "required": false; }; "presentationModeGlobal": { "alias": "presentationModeGlobal"; "required": false; }; "presentation": { "alias": "presentation"; "required": false; }; "presentationPreset": { "alias": "presentationPreset"; "required": false; }; "sectionDefaultAppearance": { "alias": "sectionDefaultAppearance"; "required": false; }; "sectionDivider": { "alias": "sectionDivider"; "required": false; }; "visibleGlobal": { "alias": "visibleGlobal"; "required": false; }; "fieldIconPolicy": { "alias": "fieldIconPolicy"; "required": false; }; "domainRules": { "alias": "domainRules"; "required": false; }; "customEndpoints": { "alias": "customEndpoints"; "required": false; }; }, { "formSubmit": "formSubmit"; "formCancel": "formCancel"; "formReset": "formReset"; "configChange": "configChange"; "configPatchChange": "configPatchChange"; "formReady": "formReady"; "valueChange": "valueChange"; "payloadPreviewChange": "payloadPreviewChange"; "syncCompleted": "syncCompleted"; "initializationError": "initializationError"; "loadingStateChange": "loadingStateChange"; "enableCustomizationChange": "enableCustomizationChange"; "customAction": "customAction"; "actionConfirmation": "actionConfirmation"; "schemaStatusChange": "schemaStatusChange"; "fieldRenderError": "fieldRenderError"; "ruleDiagnosticsChange": "ruleDiagnosticsChange"; "reactiveDeterminationExecuted": "reactiveDeterminationExecuted"; "reactiveDeterminationPendingChange": "reactiveDeterminationPendingChange"; "tabChange": "tabChange"; "tabSelected": "tabSelected"; }, never, never, true, never>;
1641
+ static ɵcmp: i0.ɵɵComponentDeclaration<PraxisDynamicForm, "praxis-dynamic-form", never, { "resourcePath": { "alias": "resourcePath"; "required": false; }; "resourceId": { "alias": "resourceId"; "required": false; }; "initialValue": { "alias": "initialValue"; "required": false; }; "emptyState": { "alias": "emptyState"; "required": false; }; "editorialContext": { "alias": "editorialContext"; "required": false; }; "mode": { "alias": "mode"; "required": false; }; "config": { "alias": "config"; "required": false; }; "actions": { "alias": "actions"; "required": false; }; "schemaSource": { "alias": "schemaSource"; "required": false; }; "actionId": { "alias": "actionId"; "required": false; }; "operationId": { "alias": "operationId"; "required": false; }; "schemaUrl": { "alias": "schemaUrl"; "required": false; }; "readUrl": { "alias": "readUrl"; "required": false; }; "submitUrl": { "alias": "submitUrl"; "required": false; }; "submitMethod": { "alias": "submitMethod"; "required": false; }; "submitIdempotencyKey": { "alias": "submitIdempotencyKey"; "required": false; }; "submitCorrelationId": { "alias": "submitCorrelationId"; "required": false; }; "submitResourceVersion": { "alias": "submitResourceVersion"; "required": false; }; "submitResourceVersionTargetResourceKey": { "alias": "submitResourceVersionTargetResourceKey"; "required": false; }; "submitResourceVersionTargetIdField": { "alias": "submitResourceVersionTargetIdField"; "required": false; }; "responseSchemaUrl": { "alias": "responseSchemaUrl"; "required": false; }; "apiEndpointKey": { "alias": "apiEndpointKey"; "required": false; }; "apiUrlEntry": { "alias": "apiUrlEntry"; "required": false; }; "enableCustomization": { "alias": "enableCustomization"; "required": false; }; "showAiAssistant": { "alias": "showAiAssistant"; "required": false; }; "formId": { "alias": "formId"; "required": false; }; "componentInstanceId": { "alias": "componentInstanceId"; "required": false; }; "configPersistenceStrategy": { "alias": "configPersistenceStrategy"; "required": false; }; "layout": { "alias": "layout"; "required": false; }; "layoutMode": { "alias": "layoutMode"; "required": false; }; "formLayout": { "alias": "formLayout"; "required": false; }; "generatedLayoutPreset": { "alias": "generatedLayoutPreset"; "required": false; }; "layoutPolicy": { "alias": "layoutPolicy"; "required": false; }; "backConfig": { "alias": "backConfig"; "required": false; }; "hooks": { "alias": "hooks"; "required": false; }; "removeEmptyContainersOnSave": { "alias": "removeEmptyContainersOnSave"; "required": false; }; "reactiveValidation": { "alias": "reactiveValidation"; "required": false; }; "reactiveValidationDebounceMs": { "alias": "reactiveValidationDebounceMs"; "required": false; }; "notifyIfOutdated": { "alias": "notifyIfOutdated"; "required": false; }; "snoozeMs": { "alias": "snoozeMs"; "required": false; }; "autoOpenSettingsOnOutdated": { "alias": "autoOpenSettingsOnOutdated"; "required": false; }; "readonlyModeGlobal": { "alias": "readonlyModeGlobal"; "required": false; }; "disabledModeGlobal": { "alias": "disabledModeGlobal"; "required": false; }; "presentationModeGlobal": { "alias": "presentationModeGlobal"; "required": false; }; "presentation": { "alias": "presentation"; "required": false; }; "presentationPreset": { "alias": "presentationPreset"; "required": false; }; "sectionDefaultAppearance": { "alias": "sectionDefaultAppearance"; "required": false; }; "sectionDivider": { "alias": "sectionDivider"; "required": false; }; "visibleGlobal": { "alias": "visibleGlobal"; "required": false; }; "fieldIconPolicy": { "alias": "fieldIconPolicy"; "required": false; }; "domainRules": { "alias": "domainRules"; "required": false; }; "customEndpoints": { "alias": "customEndpoints"; "required": false; }; }, { "formSubmit": "formSubmit"; "formCancel": "formCancel"; "formReset": "formReset"; "configChange": "configChange"; "configPatchChange": "configPatchChange"; "formReady": "formReady"; "valueChange": "valueChange"; "payloadPreviewChange": "payloadPreviewChange"; "syncCompleted": "syncCompleted"; "initializationError": "initializationError"; "loadingStateChange": "loadingStateChange"; "enableCustomizationChange": "enableCustomizationChange"; "customAction": "customAction"; "actionConfirmation": "actionConfirmation"; "schemaStatusChange": "schemaStatusChange"; "fieldRenderError": "fieldRenderError"; "ruleDiagnosticsChange": "ruleDiagnosticsChange"; "reactiveDeterminationExecuted": "reactiveDeterminationExecuted"; "reactiveDeterminationPendingChange": "reactiveDeterminationPendingChange"; "tabChange": "tabChange"; "tabSelected": "tabSelected"; }, never, never, true, never>;
1637
1642
  }
1638
1643
 
1639
1644
  declare class FormConfigService {