@oondemand/oon-core-front 0.3.42 → 0.3.44

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.
package/dist/index.js CHANGED
@@ -1,3 +1,7 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
+
1
5
  // src/start.tsx
2
6
  import { StrictMode } from "react";
3
7
  import { createRoot } from "react-dom/client";
@@ -677,15 +681,30 @@ function formOptions(field) {
677
681
  }
678
682
  return void 0;
679
683
  }
684
+ function formReadonly(field) {
685
+ const raw = field;
686
+ return Boolean(raw.readonly || raw.immutable || raw.computed);
687
+ }
688
+ function formComputed(field) {
689
+ const raw = field;
690
+ if (!raw.computed || typeof raw.computed !== "object" || Array.isArray(raw.computed)) return void 0;
691
+ return raw.computed;
692
+ }
680
693
  function formFieldsFromMeta(fields) {
681
- return fields.filter(isEditableField).map((field) => ({
682
- field: field.name,
683
- label: fieldLabel(field),
684
- kind: field.kind,
685
- required: formRequired(field),
686
- options: formOptions(field),
687
- ref: field.ref
688
- }));
694
+ return fields.filter(isEditableField).map((field) => {
695
+ const computed = formComputed(field);
696
+ const readonly = formReadonly(field);
697
+ return {
698
+ field: field.name,
699
+ label: fieldLabel(field),
700
+ kind: field.kind,
701
+ required: formRequired(field),
702
+ options: formOptions(field),
703
+ ref: field.ref,
704
+ ...readonly ? { readonly: true } : {},
705
+ ...computed ? { computed } : {}
706
+ };
707
+ });
689
708
  }
690
709
  function formatCell(value, kind) {
691
710
  if (value == null || value === "") return "\u2014";
@@ -964,6 +983,264 @@ function DataGrid({
964
983
  import { useEffect as useEffect4, useMemo as useMemo4, useState as useState5 } from "react";
965
984
  import { Box as Box4, Button as Button4, Flex as Flex4, Heading as Heading2, Input as Input3, NativeSelect as NativeSelect2, SimpleGrid, Stack as Stack2, Text as Text5, Textarea } from "@chakra-ui/react";
966
985
 
986
+ // src/domain/domainExpressions.ts
987
+ var DomainExpressionError = class extends Error {
988
+ constructor(message, options = {}) {
989
+ super(message);
990
+ __publicField(this, "code");
991
+ __publicField(this, "field");
992
+ this.name = "DomainExpressionError";
993
+ this.code = options.code ?? "OON_DOMAIN_EXPRESSION_INVALID";
994
+ this.field = options.field;
995
+ }
996
+ };
997
+ var NUMERIC_KINDS = /* @__PURE__ */ new Set(["number", "currency", "currencyConverted"]);
998
+ function hasOwn(object, key) {
999
+ return Object.prototype.hasOwnProperty.call(object, key);
1000
+ }
1001
+ function isEmpty(value) {
1002
+ return value === null || value === void 0 || typeof value === "string" && !value.trim();
1003
+ }
1004
+ function getFieldValue(record, fieldPath) {
1005
+ const parts = String(fieldPath).split(".");
1006
+ let current = record;
1007
+ for (const part of parts) {
1008
+ if (["__proto__", "prototype", "constructor"].includes(part)) return void 0;
1009
+ if (current === null || current === void 0 || typeof current !== "object") return void 0;
1010
+ current = current[part];
1011
+ }
1012
+ return current;
1013
+ }
1014
+ function toNumber(value, context = {}) {
1015
+ if (isEmpty(value)) return context.nullAsZero ? 0 : null;
1016
+ const numeric = typeof value === "number" ? value : Number(value);
1017
+ if (!Number.isFinite(numeric)) {
1018
+ throw new DomainExpressionError(
1019
+ `A f\xF3rmula do campo ${context.field ?? "calculado"} recebeu um valor n\xE3o num\xE9rico.`,
1020
+ { code: "OON_DOMAIN_FORMULA_ERROR", field: context.field }
1021
+ );
1022
+ }
1023
+ return numeric;
1024
+ }
1025
+ function numericArguments(args, record, context) {
1026
+ const values = args.map((arg) => evaluateDomainExpression(arg, record, context));
1027
+ if (!context.nullAsZero && values.some(isEmpty)) return null;
1028
+ return values.map((value) => toNumber(value, context) ?? 0);
1029
+ }
1030
+ function compareValues(leftValue, rightValue, operator) {
1031
+ let left = leftValue;
1032
+ let right = rightValue;
1033
+ if (["gt", "gte", "lt", "lte"].includes(operator)) {
1034
+ const leftNumber = Number(left);
1035
+ const rightNumber = Number(right);
1036
+ if (Number.isFinite(leftNumber) && Number.isFinite(rightNumber)) {
1037
+ left = leftNumber;
1038
+ right = rightNumber;
1039
+ }
1040
+ }
1041
+ switch (operator) {
1042
+ case "eq":
1043
+ return Object.is(left, right);
1044
+ case "neq":
1045
+ return !Object.is(left, right);
1046
+ case "gt":
1047
+ return left > right;
1048
+ case "gte":
1049
+ return left >= right;
1050
+ case "lt":
1051
+ return left < right;
1052
+ case "lte":
1053
+ return left <= right;
1054
+ default:
1055
+ return false;
1056
+ }
1057
+ }
1058
+ function evaluateDomainExpression(expression, record = {}, context = {}) {
1059
+ if (!expression || typeof expression !== "object" || Array.isArray(expression)) {
1060
+ throw new DomainExpressionError("Express\xE3o declarativa inv\xE1lida.", { field: context.field });
1061
+ }
1062
+ if (hasOwn(expression, "value")) return expression.value;
1063
+ if (hasOwn(expression, "field")) return getFieldValue(record, expression.field);
1064
+ const operation = expression;
1065
+ const args = Array.isArray(operation.args) ? operation.args : [];
1066
+ switch (operation.op) {
1067
+ case "add": {
1068
+ const values = numericArguments(args, record, context);
1069
+ return values === null ? null : values.reduce((total, value) => total + value, 0);
1070
+ }
1071
+ case "subtract": {
1072
+ const values = numericArguments(args, record, context);
1073
+ return values === null ? null : values.slice(1).reduce((total, value) => total - value, values[0] ?? 0);
1074
+ }
1075
+ case "multiply": {
1076
+ const values = numericArguments(args, record, context);
1077
+ return values === null ? null : values.reduce((total, value) => total * value, 1);
1078
+ }
1079
+ case "divide": {
1080
+ const values = numericArguments(args, record, context);
1081
+ if (values === null) return null;
1082
+ return values.slice(1).reduce((total, divisor) => {
1083
+ if (divisor === 0) {
1084
+ throw new DomainExpressionError(
1085
+ `A f\xF3rmula do campo ${context.field ?? "calculado"} tentou dividir por zero.`,
1086
+ { code: "OON_DOMAIN_FORMULA_ERROR", field: context.field }
1087
+ );
1088
+ }
1089
+ return total / divisor;
1090
+ }, values[0] ?? 0);
1091
+ }
1092
+ case "min": {
1093
+ const values = numericArguments(args, record, context);
1094
+ return values === null ? null : Math.min(...values);
1095
+ }
1096
+ case "max": {
1097
+ const values = numericArguments(args, record, context);
1098
+ return values === null ? null : Math.max(...values);
1099
+ }
1100
+ case "abs": {
1101
+ const values = numericArguments(args, record, context);
1102
+ return values === null ? null : Math.abs(values[0] ?? 0);
1103
+ }
1104
+ case "negate": {
1105
+ const values = numericArguments(args, record, context);
1106
+ return values === null ? null : -(values[0] ?? 0);
1107
+ }
1108
+ case "coalesce": {
1109
+ for (const arg of args) {
1110
+ const value = evaluateDomainExpression(arg, record, context);
1111
+ if (!isEmpty(value)) return value;
1112
+ }
1113
+ return null;
1114
+ }
1115
+ case "eq":
1116
+ case "neq":
1117
+ case "gt":
1118
+ case "gte":
1119
+ case "lt":
1120
+ case "lte":
1121
+ return compareValues(
1122
+ evaluateDomainExpression(args[0], record, context),
1123
+ evaluateDomainExpression(args[1], record, context),
1124
+ operation.op
1125
+ );
1126
+ case "and":
1127
+ return args.every((arg) => Boolean(evaluateDomainExpression(arg, record, context)));
1128
+ case "or":
1129
+ return args.some((arg) => Boolean(evaluateDomainExpression(arg, record, context)));
1130
+ case "not":
1131
+ return !Boolean(evaluateDomainExpression(args[0], record, context));
1132
+ case "present":
1133
+ return !isEmpty(evaluateDomainExpression(args[0], record, context));
1134
+ case "in": {
1135
+ const value = evaluateDomainExpression(args[0], record, context);
1136
+ const list = evaluateDomainExpression(args[1], record, context);
1137
+ return Array.isArray(list) && list.some((item) => Object.is(item, value));
1138
+ }
1139
+ default:
1140
+ throw new DomainExpressionError(`Operador declarativo n\xE3o suportado: ${String(operation.op)}.`, {
1141
+ field: context.field
1142
+ });
1143
+ }
1144
+ }
1145
+ function roundValue(value, precision = 0) {
1146
+ if (value === null || value === void 0) return value;
1147
+ const numeric = toNumber(value);
1148
+ if (numeric === null) return null;
1149
+ const factor = 10 ** precision;
1150
+ return Math.round((numeric + Number.EPSILON) * factor) / factor;
1151
+ }
1152
+ function expressionFieldReferences(expression, references = /* @__PURE__ */ new Set()) {
1153
+ if (hasOwn(expression, "field")) references.add(expression.field);
1154
+ if (hasOwn(expression, "op")) {
1155
+ for (const argument of expression.args ?? []) {
1156
+ expressionFieldReferences(argument, references);
1157
+ }
1158
+ }
1159
+ return references;
1160
+ }
1161
+ function orderComputedFields(fields) {
1162
+ const computed = fields.filter((field) => field.computed);
1163
+ const computedByName = new Map(computed.map((field) => [field.field, field]));
1164
+ const allNames = new Set(fields.map((field) => field.field));
1165
+ const visiting = /* @__PURE__ */ new Set();
1166
+ const visited = /* @__PURE__ */ new Set();
1167
+ const ordered = [];
1168
+ const visit = (field) => {
1169
+ if (visited.has(field.field)) return;
1170
+ if (visiting.has(field.field)) {
1171
+ throw new DomainExpressionError(`Depend\xEAncia circular em campos calculados envolvendo ${field.field}.`, {
1172
+ field: field.field
1173
+ });
1174
+ }
1175
+ visiting.add(field.field);
1176
+ for (const reference of expressionFieldReferences(field.computed.expression)) {
1177
+ if (!allNames.has(reference)) {
1178
+ throw new DomainExpressionError(`A f\xF3rmula de ${field.field} referencia o campo inexistente ${reference}.`, {
1179
+ field: field.field
1180
+ });
1181
+ }
1182
+ const dependency = computedByName.get(reference);
1183
+ if (dependency) visit(dependency);
1184
+ }
1185
+ visiting.delete(field.field);
1186
+ visited.add(field.field);
1187
+ ordered.push(field);
1188
+ };
1189
+ computed.forEach(visit);
1190
+ return ordered;
1191
+ }
1192
+ function coerceDomainFormValue(value, kind) {
1193
+ if (value === "") return void 0;
1194
+ if (NUMERIC_KINDS.has(kind ?? "")) return Number(value);
1195
+ if (kind === "boolean") return value === "true";
1196
+ return value;
1197
+ }
1198
+ function displayFormValue(value) {
1199
+ if (value === null || value === void 0) return "";
1200
+ return String(value);
1201
+ }
1202
+ function applyReactiveFormulas(fields, currentValues) {
1203
+ const values = { ...currentValues };
1204
+ const errors = {};
1205
+ const record = {};
1206
+ for (const field of fields) {
1207
+ record[field.field] = coerceDomainFormValue(values[field.field] ?? "", field.kind);
1208
+ }
1209
+ let ordered;
1210
+ try {
1211
+ ordered = orderComputedFields(fields);
1212
+ } catch (error) {
1213
+ const issue = error instanceof DomainExpressionError ? error : new DomainExpressionError(String(error));
1214
+ if (issue.field) errors[issue.field] = issue.message;
1215
+ return { values, errors };
1216
+ }
1217
+ for (const field of ordered) {
1218
+ try {
1219
+ const computed = field.computed;
1220
+ const value = evaluateDomainExpression(computed.expression, record, {
1221
+ field: field.field,
1222
+ nullAsZero: computed.nullAsZero !== false
1223
+ });
1224
+ const normalized2 = value === null || value === void 0 ? value : roundValue(value, computed.precision ?? 2);
1225
+ record[field.field] = normalized2;
1226
+ values[field.field] = displayFormValue(normalized2);
1227
+ } catch (error) {
1228
+ const issue = error instanceof DomainExpressionError ? error : new DomainExpressionError(String(error), { field: field.field });
1229
+ errors[field.field] = issue.message;
1230
+ }
1231
+ }
1232
+ return { values, errors };
1233
+ }
1234
+ function buildDomainMutationPayload(fields, values) {
1235
+ const payload = {};
1236
+ for (const field of fields) {
1237
+ if (field.readonly || field.computed) continue;
1238
+ const value = coerceDomainFormValue(values[field.field] ?? "", field.kind);
1239
+ if (value !== void 0) payload[field.field] = value;
1240
+ }
1241
+ return payload;
1242
+ }
1243
+
967
1244
  // src/components/internal/ReferenceSelect.tsx
968
1245
  import { useEffect as useEffect3, useMemo as useMemo3, useRef, useState as useState4 } from "react";
969
1246
  import { Box as Box3, Button as Button3, Flex as Flex3, Input as Input2, Spinner as Spinner2, Stack, Text as Text4 } from "@chakra-ui/react";
@@ -1512,16 +1789,16 @@ function toValue(value, kind) {
1512
1789
  function initialFieldValue(field, value) {
1513
1790
  return normalizeMaskedValue(toValue(value, field.kind), resolveInputMask(field));
1514
1791
  }
1515
- function coerce(value, kind) {
1516
- if (value === "") return void 0;
1517
- if (["number", "currency", "currencyConverted"].includes(kind ?? "")) return Number(value);
1518
- if (kind === "boolean") return value === "true";
1519
- return value;
1792
+ function initialReactiveValues(fields, initialValues) {
1793
+ const initial = Object.fromEntries(fields.map((field) => [field.field, initialFieldValue(field, initialValues?.[field.field])]));
1794
+ return applyReactiveFormulas(fields, initial);
1520
1795
  }
1521
1796
  function validate(fields, values) {
1522
1797
  const errors = {};
1523
1798
  fields.forEach((field) => {
1524
- if (field.required && !(values[field.field] ?? "").trim()) errors[field.field] = `${fieldLabel({ name: field.field, label: field.label })} \xE9 obrigat\xF3rio.`;
1799
+ if (!field.readonly && !field.computed && field.required && !(values[field.field] ?? "").trim()) {
1800
+ errors[field.field] = `${fieldLabel({ name: field.field, label: field.label })} \xE9 obrigat\xF3rio.`;
1801
+ }
1525
1802
  });
1526
1803
  return errors;
1527
1804
  }
@@ -1572,21 +1849,22 @@ function focusField(field) {
1572
1849
  function isMultiline(field) {
1573
1850
  return field.multiline === true || /observa|descricao|mensagem|detalhe|necessidade/i.test(field.field);
1574
1851
  }
1575
- function Label({ id, label, required }) {
1852
+ function Label({ id, label, required, readonly }) {
1576
1853
  return /* @__PURE__ */ jsx9("label", { htmlFor: id, children: /* @__PURE__ */ jsxs5(Text5, { as: "span", display: "block", mb: "6px", color: "#475467", fontSize: "11px", fontWeight: "600", children: [
1577
1854
  label,
1578
- required ? /* @__PURE__ */ jsx9(Text5, { as: "span", color: "#DC2626", children: " *" }) : null
1855
+ required && !readonly ? /* @__PURE__ */ jsx9(Text5, { as: "span", color: "#DC2626", children: " *" }) : null,
1856
+ readonly ? /* @__PURE__ */ jsx9(Text5, { as: "span", ml: "5px", color: "#98A2B3", fontSize: "9px", fontWeight: "500", children: "somente leitura" }) : null
1579
1857
  ] }) });
1580
1858
  }
1581
1859
  function ErrorText({ id, text }) {
1582
1860
  return text ? /* @__PURE__ */ jsx9(Text5, { id, role: "alert", mt: "5px", color: "#DC2626", fontSize: "10px", fontWeight: "500", children: text }) : null;
1583
1861
  }
1584
- var controlProps = (invalid) => ({
1862
+ var controlProps = (invalid, readonly = false) => ({
1585
1863
  minH: "37px",
1586
1864
  px: "10px",
1587
1865
  py: "8px",
1588
1866
  color: "#475467",
1589
- bg: "white",
1867
+ bg: readonly ? "#F8FAFC" : "white",
1590
1868
  borderColor: invalid ? "#DC2626" : "#D5DDE3",
1591
1869
  borderRadius: "6px",
1592
1870
  boxShadow: invalid ? "0 0 0 3px rgba(220,38,38,.08)" : void 0,
@@ -1616,11 +1894,14 @@ function resolveReference(field, values) {
1616
1894
  });
1617
1895
  return { filters, disabled: missing.length > 0 };
1618
1896
  }
1619
- function DynamicForm({ title, eyebrow = "Cadastro", fields, initialValues, submitting, error, onSubmit, onCancel, onFieldChange }) {
1620
- const [values, setValues] = useState5(() => Object.fromEntries(fields.map((field) => [field.field, initialFieldValue(field, initialValues?.[field.field])])));
1897
+ function DynamicForm({ title, eyebrow = "Cadastro", fields: rawFields, initialValues, submitting, error, onSubmit, onCancel, onFieldChange }) {
1898
+ const fields = rawFields;
1899
+ const initial = initialReactiveValues(fields, initialValues);
1900
+ const [values, setValues] = useState5(initial.values);
1901
+ const [formulaErrors, setFormulaErrors] = useState5(initial.errors);
1621
1902
  const [errors, setErrors] = useState5({});
1622
1903
  const [dismissed, setDismissed] = useState5(false);
1623
- const items = useMemo4(() => buildItems(fields), [fields]);
1904
+ const items = useMemo4(() => buildItems(fields), [rawFields]);
1624
1905
  useEffect4(() => {
1625
1906
  const listener = (event) => {
1626
1907
  if (event.key !== "Escape" || event.defaultPrevented || submitting) return;
@@ -1642,8 +1923,9 @@ function DynamicForm({ title, eyebrow = "Cadastro", fields, initialValues, submi
1642
1923
  if (first) focusField(first.field);
1643
1924
  }, [error]);
1644
1925
  const change = (fieldName, value) => {
1645
- const extendedFields = fields;
1646
- const dependentFields = extendedFields.filter(
1926
+ const selected = fields.find((field) => field.field === fieldName);
1927
+ if (selected?.readonly || selected?.computed) return;
1928
+ const dependentFields = fields.filter(
1647
1929
  (candidate) => Object.values(candidate.referenceFilterFrom ?? {}).includes(fieldName)
1648
1930
  );
1649
1931
  setValues((current) => {
@@ -1652,7 +1934,9 @@ function DynamicForm({ title, eyebrow = "Cadastro", fields, initialValues, submi
1652
1934
  if (changed) dependentFields.forEach((candidate) => {
1653
1935
  next[candidate.field] = "";
1654
1936
  });
1655
- return next;
1937
+ const reactive = applyReactiveFormulas(fields, next);
1938
+ setFormulaErrors(reactive.errors);
1939
+ return reactive.values;
1656
1940
  });
1657
1941
  setErrors((current) => {
1658
1942
  const next = { ...current };
@@ -1673,23 +1957,19 @@ function DynamicForm({ title, eyebrow = "Cadastro", fields, initialValues, submi
1673
1957
  if (first) focusField(first.field);
1674
1958
  return;
1675
1959
  }
1676
- const payload = {};
1677
- fields.forEach((field) => {
1678
- const value = coerce(values[field.field] ?? "", field.kind);
1679
- if (value !== void 0) payload[field.field] = value;
1680
- });
1681
1960
  setErrors({});
1682
- onSubmit(payload);
1961
+ onSubmit(buildDomainMutationPayload(fields, values));
1683
1962
  };
1684
1963
  const renderField = (field, grouped = false) => {
1685
1964
  const label = fieldLabel({ name: field.field, label: field.label });
1686
- const message = errors[field.field];
1965
+ const message = errors[field.field] ?? formulaErrors[field.field];
1687
1966
  const id = idFor(field.field);
1688
1967
  const errorId = message ? errorIdFor(field.field) : void 0;
1689
1968
  const multiline = isMultiline(field);
1690
1969
  const span = field.span === 2 || multiline;
1970
+ const readonly = Boolean(field.readonly || field.computed);
1691
1971
  const wrap = (control, showLabel = true) => /* @__PURE__ */ jsxs5(Box4, { minW: grouped ? "150px" : void 0, flex: grouped ? "0 1 auto" : void 0, gridColumn: !grouped && span ? "1 / -1" : void 0, children: [
1692
- showLabel ? /* @__PURE__ */ jsx9(Label, { id, label, required: field.required }) : null,
1972
+ showLabel ? /* @__PURE__ */ jsx9(Label, { id, label, required: field.required, readonly }) : null,
1693
1973
  control,
1694
1974
  /* @__PURE__ */ jsx9(ErrorText, { id: errorId, text: message })
1695
1975
  ] }, field.field);
@@ -1698,89 +1978,46 @@ function DynamicForm({ title, eyebrow = "Cadastro", fields, initialValues, submi
1698
1978
  const uncheckedValue = String(field.uncheckedValue ?? false);
1699
1979
  const checked = (values[field.field] ?? uncheckedValue) === checkedValue;
1700
1980
  return wrap(
1701
- /* @__PURE__ */ jsxs5(
1702
- Box4,
1703
- {
1704
- as: "label",
1705
- display: "flex",
1706
- minH: "37px",
1707
- px: "11px",
1708
- alignItems: "center",
1709
- gap: "8px",
1710
- color: "#344054",
1711
- bg: checked ? "#F0F7FF" : "white",
1712
- borderWidth: "1px",
1713
- borderColor: message ? "#DC2626" : checked ? "#8FC9E7" : "#D5DDE3",
1714
- borderRadius: "7px",
1715
- cursor: "pointer",
1716
- transition: "background .15s ease, border-color .15s ease",
1717
- _hover: { borderColor: "#8FC9E7", bg: "#F7FBFE" },
1718
- children: [
1719
- /* @__PURE__ */ jsx9(
1720
- "input",
1721
- {
1722
- id,
1723
- type: "checkbox",
1724
- checked,
1725
- "aria-invalid": !!message,
1726
- "aria-describedby": errorId,
1727
- style: { width: 16, height: 16, accentColor: "#0474AF", cursor: "pointer" },
1728
- onChange: (event) => change(field.field, event.currentTarget.checked ? checkedValue : uncheckedValue)
1729
- }
1730
- ),
1731
- /* @__PURE__ */ jsxs5(Text5, { as: "span", fontSize: "11px", fontWeight: "600", children: [
1732
- label,
1733
- field.required ? /* @__PURE__ */ jsx9(Text5, { as: "span", color: "#DC2626", children: " *" }) : null
1734
- ] })
1735
- ]
1736
- }
1737
- ),
1981
+ /* @__PURE__ */ jsxs5(Box4, { as: "label", display: "flex", minH: "37px", px: "11px", alignItems: "center", gap: "8px", color: "#344054", bg: readonly ? "#F8FAFC" : checked ? "#F0F7FF" : "white", borderWidth: "1px", borderColor: message ? "#DC2626" : checked ? "#8FC9E7" : "#D5DDE3", borderRadius: "7px", cursor: readonly ? "not-allowed" : "pointer", transition: "background .15s ease, border-color .15s ease", children: [
1982
+ /* @__PURE__ */ jsx9("input", { id, type: "checkbox", checked, disabled: readonly, "aria-invalid": !!message, "aria-describedby": errorId, style: { width: 16, height: 16, accentColor: "#0474AF", cursor: readonly ? "not-allowed" : "pointer" }, onChange: (event) => change(field.field, event.currentTarget.checked ? checkedValue : uncheckedValue) }),
1983
+ /* @__PURE__ */ jsxs5(Text5, { as: "span", fontSize: "11px", fontWeight: "600", children: [
1984
+ label,
1985
+ field.required && !readonly ? /* @__PURE__ */ jsx9(Text5, { as: "span", color: "#DC2626", children: " *" }) : null
1986
+ ] })
1987
+ ] }),
1738
1988
  false
1739
1989
  );
1740
1990
  }
1741
1991
  if (field.kind === "ref" && field.ref) {
1742
1992
  const reference = resolveReference(field, values);
1743
- return wrap(/* @__PURE__ */ jsx9(ReferenceSelect, { field: field.field, inputId: id, errorId, label, refModel: field.ref, value: values[field.field] ?? "", initialValue: initialValues?.[field.field], required: field.required, invalid: !!message, error: message, filters: reference.filters, emptyFields: field.referenceEmptyFields, disabled: reference.disabled, disabledMessage: field.referenceDisabledMessage, onChange: (value2) => change(field.field, value2) }));
1993
+ return wrap(/* @__PURE__ */ jsx9(ReferenceSelect, { field: field.field, inputId: id, errorId, label, refModel: field.ref, value: values[field.field] ?? "", initialValue: initialValues?.[field.field], required: field.required && !readonly, invalid: !!message, error: message, filters: reference.filters, emptyFields: field.referenceEmptyFields, disabled: readonly || reference.disabled, disabledMessage: field.referenceDisabledMessage, onChange: (value2) => change(field.field, value2) }));
1744
1994
  }
1745
- if (field.kind === "enum" && field.options?.length) return wrap(/* @__PURE__ */ jsxs5(NativeSelect2.Root, { size: "sm", children: [
1746
- /* @__PURE__ */ jsxs5(NativeSelect2.Field, { id, "aria-invalid": !!message, "aria-describedby": errorId, value: values[field.field] ?? "", ...controlProps(!!message), onChange: (event) => change(field.field, event.currentTarget.value), children: [
1995
+ if (field.kind === "enum" && field.options?.length) return wrap(/* @__PURE__ */ jsxs5(NativeSelect2.Root, { size: "sm", disabled: readonly, children: [
1996
+ /* @__PURE__ */ jsxs5(NativeSelect2.Field, { id, "aria-invalid": !!message, "aria-describedby": errorId, value: values[field.field] ?? "", ...controlProps(!!message, readonly), onChange: (event) => change(field.field, event.currentTarget.value), children: [
1747
1997
  /* @__PURE__ */ jsx9("option", { value: "", children: "\u2014 Selecione \u2014" }),
1748
1998
  field.options.map((option) => /* @__PURE__ */ jsx9("option", { value: option, children: option }, option))
1749
1999
  ] }),
1750
2000
  /* @__PURE__ */ jsx9(NativeSelect2.Indicator, {})
1751
2001
  ] }));
1752
- if (field.kind === "boolean") return wrap(/* @__PURE__ */ jsxs5(NativeSelect2.Root, { size: "sm", children: [
1753
- /* @__PURE__ */ jsxs5(NativeSelect2.Field, { id, "aria-invalid": !!message, "aria-describedby": errorId, value: values[field.field] ?? "", ...controlProps(!!message), onChange: (event) => change(field.field, event.currentTarget.value), children: [
2002
+ if (field.kind === "boolean") return wrap(/* @__PURE__ */ jsxs5(NativeSelect2.Root, { size: "sm", disabled: readonly, children: [
2003
+ /* @__PURE__ */ jsxs5(NativeSelect2.Field, { id, "aria-invalid": !!message, "aria-describedby": errorId, value: values[field.field] ?? "", ...controlProps(!!message, readonly), onChange: (event) => change(field.field, event.currentTarget.value), children: [
1754
2004
  /* @__PURE__ */ jsx9("option", { value: "", children: "\u2014 Selecione \u2014" }),
1755
2005
  /* @__PURE__ */ jsx9("option", { value: "true", children: "Sim" }),
1756
2006
  /* @__PURE__ */ jsx9("option", { value: "false", children: "N\xE3o" })
1757
2007
  ] }),
1758
2008
  /* @__PURE__ */ jsx9(NativeSelect2.Indicator, {})
1759
2009
  ] }));
1760
- if (multiline) return wrap(/* @__PURE__ */ jsx9(Textarea, { id, rows: field.rows ?? 4, resize: "vertical", "aria-invalid": !!message, "aria-describedby": errorId, value: values[field.field] ?? "", ...controlProps(!!message), lineHeight: "1.5", onChange: (event) => change(field.field, event.currentTarget.value) }));
2010
+ if (multiline) return wrap(/* @__PURE__ */ jsx9(Textarea, { id, rows: field.rows ?? 4, resize: "vertical", readOnly: readonly, "aria-invalid": !!message, "aria-describedby": errorId, value: values[field.field] ?? "", ...controlProps(!!message, readonly), lineHeight: "1.5", onChange: (event) => change(field.field, event.currentTarget.value) }));
1761
2011
  const mask = resolveInputMask(field);
1762
- const type = mask ? "text" : field.kind === "date" ? "date" : field.kind === "number" ? "number" : "text";
2012
+ const numeric = ["number", "currency", "currencyConverted"].includes(field.kind ?? "");
2013
+ const type = mask ? "text" : field.kind === "date" ? "date" : numeric ? "number" : "text";
1763
2014
  const value = values[field.field] ?? "";
1764
2015
  return wrap(
1765
- /* @__PURE__ */ jsx9(
1766
- Input3,
1767
- {
1768
- id,
1769
- type,
1770
- step: type === "number" ? "any" : void 0,
1771
- inputMode: inputModeForMask(mask),
1772
- maxLength: maxLengthForMask(mask),
1773
- autoComplete: "off",
1774
- "aria-invalid": !!message,
1775
- "aria-describedby": errorId,
1776
- value: mask ? formatMaskedValue(value, mask) : value,
1777
- ...controlProps(!!message),
1778
- onChange: (event) => change(field.field, parseMaskedInput(event.currentTarget.value, mask))
1779
- }
1780
- )
2016
+ /* @__PURE__ */ jsx9(Input3, { id, type, step: type === "number" ? "any" : void 0, inputMode: inputModeForMask(mask), maxLength: maxLengthForMask(mask), autoComplete: "off", readOnly: readonly, "aria-invalid": !!message, "aria-describedby": errorId, value: mask ? formatMaskedValue(value, mask) : value, ...controlProps(!!message, readonly), onChange: (event) => change(field.field, parseMaskedInput(event.currentTarget.value, mask)) })
1781
2017
  );
1782
2018
  };
1783
- const invalid = fields.filter((field) => errors[field.field]);
2019
+ const combinedErrors = { ...formulaErrors, ...errors };
2020
+ const invalid = fields.filter((field) => combinedErrors[field.field]);
1784
2021
  const generic = dismissed ? null : messageOf(error);
1785
2022
  return /* @__PURE__ */ jsx9(Flex4, { position: "fixed", inset: 0, zIndex: 1e3, align: "center", justify: "center", p: { base: 2, md: 6 }, bg: "rgba(15,23,42,.48)", backdropFilter: "blur(2px)", onMouseDown: (event) => {
1786
2023
  if (event.currentTarget === event.target && !submitting) onCancel();
@@ -1797,12 +2034,12 @@ function DynamicForm({ title, eyebrow = "Cadastro", fields, initialValues, submi
1797
2034
  invalid.length ? /* @__PURE__ */ jsxs5(Box4, { role: "alert", p: "11px 13px", color: "#9B1C1C", bg: "#FFF5F5", borderWidth: "1px", borderColor: "#FECACA", borderLeftWidth: "4px", borderLeftColor: "#DC2626", borderRadius: "8px", fontSize: "11px", children: [
1798
2035
  /* @__PURE__ */ jsxs5(Flex4, { align: "center", gap: "7px", children: [
1799
2036
  /* @__PURE__ */ jsx9(AlertIcon, {}),
1800
- /* @__PURE__ */ jsx9(Text5, { as: "strong", children: "N\xE3o foi poss\xEDvel salvar. Corrija os campos abaixo:" })
2037
+ /* @__PURE__ */ jsx9(Text5, { as: "strong", children: "Revise os campos abaixo:" })
1801
2038
  ] }),
1802
2039
  /* @__PURE__ */ jsx9(Box4, { as: "ul", mt: "7px", mb: 0, pl: "20px", display: "grid", gap: "3px", children: invalid.map((field) => /* @__PURE__ */ jsx9("li", { children: /* @__PURE__ */ jsxs5(Button4, { type: "button", variant: "plain", minH: "auto", h: "auto", p: 0, color: "#B42318", fontSize: "10px", fontWeight: "400", textDecoration: "underline", onClick: () => focusField(field.field), children: [
1803
2040
  fieldLabel({ name: field.field, label: field.label }),
1804
2041
  ": ",
1805
- errors[field.field]
2042
+ combinedErrors[field.field]
1806
2043
  ] }) }, field.field)) })
1807
2044
  ] }) : null,
1808
2045
  generic && !invalid.length ? /* @__PURE__ */ jsxs5(Flex4, { role: "alert", p: "10px 12px", align: "center", gap: 2, color: "#B42318", bg: "#FEF3F2", borderWidth: "1px", borderColor: "#FECDCA", borderRadius: "7px", fontSize: "11px", children: [
@@ -2241,6 +2478,18 @@ function CoreRowAction({ action, row, parent, onOpenDetail, onRefresh, onUpdate
2241
2478
 
2242
2479
  // src/components/internal/CoreRelatedGrid.tsx
2243
2480
  import { Fragment as Fragment2, jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
2481
+ function parentValueAt(parent, path) {
2482
+ return path.split(".").reduce((current, part) => {
2483
+ if (!current || typeof current !== "object") return void 0;
2484
+ return current[part];
2485
+ }, parent);
2486
+ }
2487
+ function mergeCreateFields(schemaFields, overrides, foreignKey) {
2488
+ const base = schemaFields.filter((field) => ![foreignKey, "_id", "createdAt", "updatedAt"].includes(field.field));
2489
+ if (!overrides?.length) return base;
2490
+ const byName = new Map(base.map((field) => [field.field, field]));
2491
+ return overrides.map((override) => ({ ...byName.get(override.field) ?? {}, ...override }));
2492
+ }
2244
2493
  function CoreRelatedGrid({
2245
2494
  tab: rawTab,
2246
2495
  parent,
@@ -2265,6 +2514,17 @@ function CoreRelatedGrid({
2265
2514
  () => (tab.columns?.length ? tab.columns : schema?.fields.slice(0, 8).map((field) => field.name) ?? []).map((column) => normalizeColumn(column, schema)).filter((column) => !column.hidden),
2266
2515
  [tab.columns, schema]
2267
2516
  );
2517
+ const schemaFormFields = useMemo5(() => formFieldsFromMeta(schema?.fields ?? []), [schema?.fields]);
2518
+ const createFields = useMemo5(
2519
+ () => mergeCreateFields(schemaFormFields, tab.create?.fields, relation?.foreignKey),
2520
+ [schemaFormFields, tab.create?.fields, relation?.foreignKey]
2521
+ );
2522
+ const createInitialValues = useMemo5(() => {
2523
+ const inherited = Object.fromEntries(
2524
+ Object.entries(tab.create?.initialValuesFromParent ?? {}).map(([field, path]) => [field, parentValueAt(parent, path)])
2525
+ );
2526
+ return { ...tab.create?.initialValues ?? {}, ...inherited };
2527
+ }, [tab.create?.initialValues, tab.create?.initialValuesFromParent, parent]);
2268
2528
  const [drafts, setDrafts] = useState7({});
2269
2529
  const [errors, setErrors] = useState7({});
2270
2530
  const [creating, setCreating] = useState7(false);
@@ -2283,7 +2543,7 @@ function CoreRelatedGrid({
2283
2543
  });
2284
2544
  const createMutation = useMutation({
2285
2545
  mutationFn: (values) => resource.create({
2286
- ...tab.create?.initialValues ?? {},
2546
+ ...createInitialValues,
2287
2547
  ...values,
2288
2548
  ...relation && parentValue != null ? { [relation.foreignKey]: parentValue } : {}
2289
2549
  }),
@@ -2305,7 +2565,6 @@ function CoreRelatedGrid({
2305
2565
  ...current,
2306
2566
  [id]: { ...current[id] ?? {}, [field]: value }
2307
2567
  }));
2308
- const createFields = tab.create?.fields?.length ? tab.create.fields : formFieldsFromMeta(schema?.fields ?? []).filter((field) => ![relation.foreignKey, "_id", "createdAt", "updatedAt"].includes(field.field));
2309
2568
  return /* @__PURE__ */ jsxs9(Box7, { children: [
2310
2569
  canCreate ? /* @__PURE__ */ jsx14(Flex5, { justify: "flex-end", mb: "10px", children: /* @__PURE__ */ jsx14(Button6, { size: "sm", colorPalette: "brand", onClick: () => {
2311
2570
  setCreateError(null);
@@ -2382,7 +2641,7 @@ function CoreRelatedGrid({
2382
2641
  title: tab.create?.label ?? `Novo ${schema?.singular ?? relation.model}`,
2383
2642
  eyebrow: "Registro relacionado",
2384
2643
  fields: createFields,
2385
- initialValues: tab.create?.initialValues,
2644
+ initialValues: createInitialValues,
2386
2645
  submitting: createMutation.isPending,
2387
2646
  error: createError,
2388
2647
  onSubmit: (values) => createMutation.mutate(values),
@@ -2397,12 +2656,6 @@ function CoreRelatedGrid({
2397
2656
 
2398
2657
  // src/components/internal/CoreTabbedDetail.tsx
2399
2658
  import { jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
2400
- function coerce2(value, kind) {
2401
- if (value === "") return void 0;
2402
- if (["number", "currency", "currencyConverted"].includes(kind ?? "")) return Number(value);
2403
- if (kind === "boolean") return value === "true";
2404
- return value;
2405
- }
2406
2659
  function toValue2(value, kind) {
2407
2660
  if (value == null) return "";
2408
2661
  if (kind === "date") {
@@ -2421,6 +2674,10 @@ function toValue2(value, kind) {
2421
2674
  function initialFieldValue2(field, value) {
2422
2675
  return normalizeMaskedValue(toValue2(value, field.kind), resolveInputMask(field));
2423
2676
  }
2677
+ function initialReactiveValues2(fields, parent) {
2678
+ const initial = Object.fromEntries(fields.map((field) => [field.field, initialFieldValue2(field, parent[field.field])]));
2679
+ return applyReactiveFormulas(fields, initial);
2680
+ }
2424
2681
  function isMultiline2(field) {
2425
2682
  return /observa|descricao|mensagem|detalhe|necessidade/i.test(field.field);
2426
2683
  }
@@ -2465,7 +2722,7 @@ function fieldErrorsOf(error) {
2465
2722
  function requiredErrors(fields, values) {
2466
2723
  const errors = {};
2467
2724
  fields.forEach((field) => {
2468
- if (field.required && !(values[field.field] ?? "").trim()) {
2725
+ if (!field.readonly && !field.computed && field.required && !(values[field.field] ?? "").trim()) {
2469
2726
  errors[field.field] = `${fieldLabel({ name: field.field, label: field.label })} \xE9 obrigat\xF3rio.`;
2470
2727
  }
2471
2728
  });
@@ -2483,9 +2740,11 @@ function resolveReference2(field, values) {
2483
2740
  }
2484
2741
  function FieldLabel({ field, htmlFor }) {
2485
2742
  const label = fieldLabel({ name: field.field, label: field.label });
2743
+ const readonly = Boolean(field.readonly || field.computed);
2486
2744
  return /* @__PURE__ */ jsx15("label", { htmlFor, children: /* @__PURE__ */ jsxs10(Text9, { as: "span", display: "block", mb: "5px", color: "#475467", fontSize: "11px", fontWeight: "600", children: [
2487
2745
  label,
2488
- field.required ? /* @__PURE__ */ jsx15(Text9, { as: "span", color: "#DC2626", children: " *" }) : null
2746
+ field.required && !readonly ? /* @__PURE__ */ jsx15(Text9, { as: "span", color: "#DC2626", children: " *" }) : null,
2747
+ readonly ? /* @__PURE__ */ jsx15(Text9, { as: "span", ml: "5px", color: "#98A2B3", fontSize: "9px", fontWeight: "500", children: "somente leitura" }) : null
2489
2748
  ] }) });
2490
2749
  }
2491
2750
  function ErrorText2({ id, message }) {
@@ -2502,11 +2761,13 @@ function FieldControl({
2502
2761
  const label = fieldLabel({ name: field.field, label: field.label });
2503
2762
  const inputId = `oon-detail-field-${field.field.replace(/[^a-zA-Z0-9_-]/g, "-")}`;
2504
2763
  const errorId = `${inputId}-error`;
2764
+ const readonly = Boolean(field.readonly || field.computed);
2505
2765
  const invalidProps = {
2506
2766
  "aria-invalid": error ? true : void 0,
2507
2767
  "aria-describedby": error ? errorId : void 0,
2508
2768
  borderColor: error ? "#DC2626" : void 0,
2509
- boxShadow: error ? "0 0 0 3px rgba(220,38,38,.08)" : void 0
2769
+ boxShadow: error ? "0 0 0 3px rgba(220,38,38,.08)" : void 0,
2770
+ bg: readonly ? "#F8FAFC" : void 0
2510
2771
  };
2511
2772
  if (field.widget === "checkbox") {
2512
2773
  const checkedValue = String(field.checkedValue ?? true);
@@ -2523,11 +2784,11 @@ function FieldControl({
2523
2784
  alignItems: "center",
2524
2785
  gap: "8px",
2525
2786
  color: "#344054",
2526
- bg: checked ? "#F0F7FF" : "white",
2787
+ bg: readonly ? "#F8FAFC" : checked ? "#F0F7FF" : "white",
2527
2788
  borderWidth: "1px",
2528
2789
  borderColor: error ? "#DC2626" : checked ? "#8FC9E7" : "#D5DDE3",
2529
2790
  borderRadius: "7px",
2530
- cursor: "pointer",
2791
+ cursor: readonly ? "not-allowed" : "pointer",
2531
2792
  children: [
2532
2793
  /* @__PURE__ */ jsx15(
2533
2794
  "input",
@@ -2535,9 +2796,10 @@ function FieldControl({
2535
2796
  id: inputId,
2536
2797
  type: "checkbox",
2537
2798
  checked,
2799
+ disabled: readonly,
2538
2800
  "aria-invalid": error ? true : void 0,
2539
2801
  "aria-describedby": error ? errorId : void 0,
2540
- style: { width: 16, height: 16, accentColor: "#0474AF", cursor: "pointer" },
2802
+ style: { width: 16, height: 16, accentColor: "#0474AF", cursor: readonly ? "not-allowed" : "pointer" },
2541
2803
  onChange: (event) => onChange(event.currentTarget.checked ? checkedValue : uncheckedValue)
2542
2804
  }
2543
2805
  ),
@@ -2562,12 +2824,12 @@ function FieldControl({
2562
2824
  refModel: field.ref,
2563
2825
  value,
2564
2826
  initialValue,
2565
- required: field.required,
2827
+ required: field.required && !readonly,
2566
2828
  invalid: !!error,
2567
2829
  error,
2568
2830
  filters: reference.filters,
2569
2831
  emptyFields: field.referenceEmptyFields,
2570
- disabled: reference.disabled,
2832
+ disabled: readonly || reference.disabled,
2571
2833
  disabledMessage: field.referenceDisabledMessage,
2572
2834
  onChange
2573
2835
  }
@@ -2575,28 +2837,29 @@ function FieldControl({
2575
2837
  ] });
2576
2838
  }
2577
2839
  const mask = resolveInputMask(field);
2578
- const control = field.kind === "enum" && field.options?.length ? /* @__PURE__ */ jsxs10(NativeSelect4.Root, { size: "sm", children: [
2840
+ const control = field.kind === "enum" && field.options?.length ? /* @__PURE__ */ jsxs10(NativeSelect4.Root, { size: "sm", disabled: readonly, children: [
2579
2841
  /* @__PURE__ */ jsxs10(NativeSelect4.Field, { id: inputId, value, ...invalidProps, onChange: (event) => onChange(event.currentTarget.value), children: [
2580
2842
  /* @__PURE__ */ jsx15("option", { value: "", children: "\u2014 Selecione \u2014" }),
2581
2843
  field.options.map((option) => /* @__PURE__ */ jsx15("option", { value: option, children: option }, option))
2582
2844
  ] }),
2583
2845
  /* @__PURE__ */ jsx15(NativeSelect4.Indicator, {})
2584
- ] }) : field.kind === "boolean" ? /* @__PURE__ */ jsxs10(NativeSelect4.Root, { size: "sm", children: [
2846
+ ] }) : field.kind === "boolean" ? /* @__PURE__ */ jsxs10(NativeSelect4.Root, { size: "sm", disabled: readonly, children: [
2585
2847
  /* @__PURE__ */ jsxs10(NativeSelect4.Field, { id: inputId, value, ...invalidProps, onChange: (event) => onChange(event.currentTarget.value), children: [
2586
2848
  /* @__PURE__ */ jsx15("option", { value: "", children: "\u2014 Selecione \u2014" }),
2587
2849
  /* @__PURE__ */ jsx15("option", { value: "true", children: "Sim" }),
2588
2850
  /* @__PURE__ */ jsx15("option", { value: "false", children: "N\xE3o" })
2589
2851
  ] }),
2590
2852
  /* @__PURE__ */ jsx15(NativeSelect4.Indicator, {})
2591
- ] }) : isMultiline2(field) ? /* @__PURE__ */ jsx15(Textarea3, { id: inputId, rows: 4, resize: "vertical", value, ...invalidProps, onChange: (event) => onChange(event.currentTarget.value) }) : /* @__PURE__ */ jsx15(
2853
+ ] }) : isMultiline2(field) ? /* @__PURE__ */ jsx15(Textarea3, { id: inputId, rows: 4, resize: "vertical", readOnly: readonly, value, ...invalidProps, onChange: (event) => onChange(event.currentTarget.value) }) : /* @__PURE__ */ jsx15(
2592
2854
  Input5,
2593
2855
  {
2594
2856
  id: inputId,
2595
2857
  size: "sm",
2596
- type: mask ? "text" : field.kind === "date" ? "date" : field.kind === "number" ? "number" : "text",
2597
- step: !mask && field.kind === "number" ? "any" : void 0,
2858
+ type: mask ? "text" : field.kind === "date" ? "date" : ["number", "currency", "currencyConverted"].includes(field.kind ?? "") ? "number" : "text",
2859
+ step: !mask && ["number", "currency", "currencyConverted"].includes(field.kind ?? "") ? "any" : void 0,
2598
2860
  inputMode: inputModeForMask(mask),
2599
2861
  maxLength: maxLengthForMask(mask),
2862
+ readOnly: readonly,
2600
2863
  value: mask ? formatMaskedValue(value, mask) : value,
2601
2864
  ...invalidProps,
2602
2865
  onChange: (event) => onChange(parseMaskedInput(event.currentTarget.value, mask))
@@ -2645,17 +2908,23 @@ function InlineParentForm({
2645
2908
  externalSubmit = false
2646
2909
  }) {
2647
2910
  const fields = rawFields;
2648
- const [values, setValues] = useState8({});
2911
+ const initial = initialReactiveValues2(fields, parent);
2912
+ const [values, setValues] = useState8(initial.values);
2913
+ const [formulaErrors, setFormulaErrors] = useState8(initial.errors);
2649
2914
  const [saving, setSaving] = useState8(false);
2650
2915
  const [error, setError] = useState8(null);
2651
2916
  const [fieldErrors, setFieldErrors] = useState8({});
2652
2917
  useEffect5(() => {
2653
- setValues(Object.fromEntries(fields.map((field) => [field.field, initialFieldValue2(field, parent[field.field])])));
2918
+ const next = initialReactiveValues2(fields, parent);
2919
+ setValues(next.values);
2920
+ setFormulaErrors(next.errors);
2654
2921
  setError(null);
2655
2922
  setFieldErrors({});
2656
2923
  }, [parent, rawFields]);
2657
2924
  const fieldsByName = useMemo6(() => new Map(fields.map((field) => [field.field, field])), [rawFields]);
2658
2925
  const change = (fieldName, value) => {
2926
+ const selected = fieldsByName.get(fieldName);
2927
+ if (selected?.readonly || selected?.computed) return;
2659
2928
  const dependentFields = fields.filter(
2660
2929
  (candidate) => Object.values(candidate.referenceFilterFrom ?? {}).includes(fieldName)
2661
2930
  );
@@ -2665,7 +2934,9 @@ function InlineParentForm({
2665
2934
  if (changed) dependentFields.forEach((candidate) => {
2666
2935
  next[candidate.field] = "";
2667
2936
  });
2668
- return next;
2937
+ const reactive = applyReactiveFormulas(fields, next);
2938
+ setFormulaErrors(reactive.errors);
2939
+ return reactive.values;
2669
2940
  });
2670
2941
  setFieldErrors((current) => {
2671
2942
  const next = { ...current };
@@ -2675,6 +2946,7 @@ function InlineParentForm({
2675
2946
  });
2676
2947
  setError(null);
2677
2948
  };
2949
+ const combinedErrors = { ...formulaErrors, ...fieldErrors };
2678
2950
  const renderFields = () => {
2679
2951
  if (groups?.length) {
2680
2952
  return /* @__PURE__ */ jsx15(Stack3, { gap: "14px", children: groups.map((group) => /* @__PURE__ */ jsx15(
@@ -2684,7 +2956,7 @@ function InlineParentForm({
2684
2956
  fields: group.fields.map((field) => fieldsByName.get(field)).filter(Boolean),
2685
2957
  values,
2686
2958
  initialValues: parent,
2687
- errors: fieldErrors,
2959
+ errors: combinedErrors,
2688
2960
  onChange: change
2689
2961
  },
2690
2962
  `${group.label}-${group.fields.join("-")}`
@@ -2697,7 +2969,7 @@ function InlineParentForm({
2697
2969
  value: values[field.field] ?? "",
2698
2970
  values,
2699
2971
  initialValue: parent[field.field],
2700
- error: fieldErrors[field.field],
2972
+ error: combinedErrors[field.field],
2701
2973
  onChange: (value) => change(field.field, value)
2702
2974
  },
2703
2975
  field.field
@@ -2720,9 +2992,7 @@ function InlineParentForm({
2720
2992
  setError(null);
2721
2993
  setFieldErrors({});
2722
2994
  try {
2723
- const payload = Object.fromEntries(
2724
- fields.map((field) => [field.field, coerce2(values[field.field] ?? "", field.kind)]).filter(([, value]) => value !== void 0)
2725
- );
2995
+ const payload = buildDomainMutationPayload(fields, values);
2726
2996
  const saved = parent._id ? await resource.update(String(parent._id), payload) : await resource.create(payload);
2727
2997
  onSaved(saved);
2728
2998
  } catch (requestError) {
@@ -5339,12 +5609,17 @@ export {
5339
5609
  CorePipeline,
5340
5610
  CoreRelationField,
5341
5611
  CoreToolbar,
5612
+ DomainExpressionError,
5342
5613
  PermissionGate,
5614
+ applyReactiveFormulas,
5615
+ buildDomainMutationPayload,
5616
+ coerceDomainFormValue,
5343
5617
  defineCollectionView,
5344
5618
  defineDashboard,
5345
5619
  defineDocumentView,
5346
5620
  defineOonModule,
5347
5621
  definePipelineView,
5622
+ evaluateDomainExpression,
5348
5623
  manifestToConfig,
5349
5624
  oonCoreFront,
5350
5625
  start,