@open-mercato/ui 0.6.5-develop.4695.1.42ee0ddf0e → 0.6.5-develop.4718.1.56d834bb34

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.
@@ -261,6 +261,9 @@ function normalizeDirtySnapshotValue(value) {
261
261
  function createDirtySnapshot(source) {
262
262
  return JSON.stringify(normalizeDirtySnapshotValue(source) ?? {});
263
263
  }
264
+ function createDirtyValueSnapshot(value) {
265
+ return JSON.stringify(normalizeDirtySnapshotValue(value) ?? null);
266
+ }
264
267
  const FIELDSET_ICON_COMPONENTS = {
265
268
  layers: Layers,
266
269
  tag: Tag,
@@ -555,6 +558,8 @@ function CrudForm({
555
558
  const clearDirtyState = React.useCallback((snapshotSource) => {
556
559
  const source = snapshotSource ?? valuesRef.current;
557
560
  dirtyBaselineSnapshotRef.current = createDirtySnapshot(source);
561
+ dirtyBaselineValuesRef.current = { ...source };
562
+ userEditedFieldIdsRef.current.clear();
558
563
  isDirtyRef.current = false;
559
564
  setHasUnsavedChanges(false);
560
565
  }, []);
@@ -1651,14 +1656,38 @@ function CrudForm({
1651
1656
  lastErrorFieldRef.current = fieldId;
1652
1657
  }
1653
1658
  }, [errors, formId]);
1659
+ const updateEditedFieldMarker = React.useCallback((id, nextValue, baselineSource = dirtyBaselineValuesRef.current) => {
1660
+ if (baselineSource && createDirtyValueSnapshot(baselineSource[id]) === createDirtyValueSnapshot(nextValue)) {
1661
+ userEditedFieldIdsRef.current.delete(id);
1662
+ return;
1663
+ }
1664
+ userEditedFieldIdsRef.current.add(id);
1665
+ }, []);
1654
1666
  const setValue = React.useCallback((id, nextValue) => {
1655
1667
  let nextData = null;
1668
+ let nextDirty = null;
1669
+ const currentValue = valuesRef.current[id];
1670
+ if (!Object.is(currentValue, nextValue)) {
1671
+ updateEditedFieldMarker(id, nextValue);
1672
+ }
1656
1673
  setValues((prev) => {
1657
1674
  if (Object.is(prev[id], nextValue)) return prev;
1675
+ const baselineSource = dirtyBaselineValuesRef.current ?? prev;
1676
+ updateEditedFieldMarker(id, nextValue, baselineSource);
1658
1677
  nextData = { ...prev, [id]: nextValue };
1659
1678
  valuesRef.current = nextData;
1679
+ if (!(embedded && !trackDirtyWhenEmbedded)) {
1680
+ const baseline = dirtyBaselineSnapshotRef.current ?? createDirtySnapshot(prev);
1681
+ dirtyBaselineSnapshotRef.current = baseline;
1682
+ dirtyBaselineValuesRef.current = baselineSource;
1683
+ nextDirty = createDirtySnapshot(nextData) !== baseline;
1684
+ }
1660
1685
  return nextData;
1661
1686
  });
1687
+ if (nextDirty !== null) {
1688
+ isDirtyRef.current = nextDirty;
1689
+ setHasUnsavedChanges(nextDirty);
1690
+ }
1662
1691
  const clearedMessages = [];
1663
1692
  setErrors((prev) => {
1664
1693
  if (!Object.keys(prev).length) return prev;
@@ -1718,7 +1747,7 @@ function CrudForm({
1718
1747
  }).catch((err) => {
1719
1748
  console.error("[CrudForm] Error in onFieldChange:", err);
1720
1749
  });
1721
- }, [extendedInjectionEventsEnabled, flash, t, translateValidationMessage, triggerInjectionEvent]);
1750
+ }, [embedded, extendedInjectionEventsEnabled, flash, t, trackDirtyWhenEmbedded, translateValidationMessage, triggerInjectionEvent, updateEditedFieldMarker]);
1722
1751
  const onBlurRequest = React.useCallback((fieldId) => {
1723
1752
  void validateFieldOnBlur(fieldId);
1724
1753
  }, [validateFieldOnBlur]);
@@ -1742,6 +1771,8 @@ function CrudForm({
1742
1771
  );
1743
1772
  const appliedInitialValuesSnapshotRef = React.useRef(void 0);
1744
1773
  const dirtyBaselineSnapshotRef = React.useRef(void 0);
1774
+ const dirtyBaselineValuesRef = React.useRef(void 0);
1775
+ const userEditedFieldIdsRef = React.useRef(/* @__PURE__ */ new Set());
1745
1776
  React.useLayoutEffect(() => {
1746
1777
  if (!initialValues) return;
1747
1778
  const snapshot = JSON.stringify({
@@ -1757,8 +1788,14 @@ function CrudForm({
1757
1788
  let hadUnsavedEdits = false;
1758
1789
  setValues((prev) => {
1759
1790
  const priorBaseline = dirtyBaselineSnapshotRef.current;
1760
- hadUnsavedEdits = priorBaseline !== void 0 && createDirtySnapshot(prev) !== priorBaseline;
1761
- const merged = { ...prev, ...initialValues };
1791
+ const editedFieldIds = userEditedFieldIdsRef.current;
1792
+ hadUnsavedEdits = editedFieldIds.size > 0 || priorBaseline !== void 0 && createDirtySnapshot(prev) !== priorBaseline;
1793
+ const merged = { ...prev };
1794
+ const mergedRecord = merged;
1795
+ for (const [key, value] of Object.entries(initialValues)) {
1796
+ if (editedFieldIds.has(key)) continue;
1797
+ mergedRecord[key] = value;
1798
+ }
1762
1799
  for (const definition of injectedFieldDefinitions) {
1763
1800
  if (merged[definition.id] !== void 0) continue;
1764
1801
  const extracted = readByDotPath(initialRecord, definition.id);
@@ -1789,6 +1826,7 @@ function CrudForm({
1789
1826
  });
1790
1827
  if (mergedValues && !hadUnsavedEdits) {
1791
1828
  dirtyBaselineSnapshotRef.current = createDirtySnapshot(mergedValues);
1829
+ dirtyBaselineValuesRef.current = { ...mergedValues };
1792
1830
  }
1793
1831
  if (!extendedInjectionEventsEnabled || !mergedValues) return;
1794
1832
  let cancelled = false;
@@ -1803,6 +1841,7 @@ function CrudForm({
1803
1841
  if (cancelled || !transformed) return;
1804
1842
  if (isDirtyRef.current) return;
1805
1843
  dirtyBaselineSnapshotRef.current = createDirtySnapshot(transformed);
1844
+ dirtyBaselineValuesRef.current = { ...transformed };
1806
1845
  setValues(transformed);
1807
1846
  } catch (err) {
1808
1847
  console.error("[CrudForm] Error in transformDisplayData:", err);
@@ -1856,6 +1895,7 @@ function CrudForm({
1856
1895
  });
1857
1896
  if (mergedValues) {
1858
1897
  dirtyBaselineSnapshotRef.current = createDirtySnapshot(mergedValues);
1898
+ dirtyBaselineValuesRef.current = { ...mergedValues };
1859
1899
  }
1860
1900
  }, [isLoading, initialValuesHasId, cfDefinitions, customEntity]);
1861
1901
  const markFormAsClean = React.useCallback((snapshotSource) => {