@pagamio/frontend-commons-lib 0.8.343 → 0.8.345

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,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useForm } from 'react-hook-form';
3
- import { useEffect, useRef, useState } from 'react';
3
+ import { useEffect, useMemo, useRef, useState } from 'react';
4
4
  import { Button, NotificationModal } from '../../components';
5
5
  import { useToast } from '../../context';
6
6
  import { FieldWrapper } from '../../form-engine';
@@ -8,21 +8,38 @@ import { useFormPersistence } from '../../form-engine/hooks/useFormPersistence';
8
8
  const DrawerContent = ({ fields, onSubmit, isOpen, initialValues, submitButtonText = 'Submit', cancelButtonText = 'Cancel', showForm = true, showDrawerButtons = true, handleCloseDrawer, onFieldUpdate, onFieldChange, children, updateFieldOptions, updateFieldLabel, setFieldHidden, addField, updateFieldValidation, processInitialFieldUpdates, processingDependencyRef, pendingUpdatesRef, persistenceKey, clearOnClose = false, isDirtyRef, cancelRef, }) => {
9
9
  const { saveFormData, restoreFormData, clearPersistedData, hasPersistedData } = useFormPersistence(persistenceKey);
10
10
  const { addToast } = useToast();
11
- // Determine initial values: initialValues take precedence over persisted data
12
- // This ensures that when editing different items, the form shows the correct item's data
11
+ // For clearOnClose drawers, seed an `{ fieldName: '' }` baseline so every
12
+ // registered input starts controlled with a defined string value. Without
13
+ // this, RHF leaves unspecified fields as `undefined`, and Radix Select
14
+ // refuses to update its visual state when we reset on close — the
15
+ // controlled→uncontrolled transition is the bug we're fixing.
16
+ // We intentionally only seed empties when clearOnClose is true: legacy
17
+ // drawers that relied on `undefined`-vs-`""` distinctions in their submit
18
+ // payload (e.g. "field omitted means don't update") keep their exact
19
+ // previous behaviour.
20
+ const emptyFieldValues = useMemo(() => {
21
+ if (!clearOnClose)
22
+ return undefined;
23
+ const acc = {};
24
+ for (const f of fields) {
25
+ acc[f.name] = '';
26
+ }
27
+ return acc;
28
+ }, [clearOnClose, fields]);
29
+ // Determine initial values: initialValues take precedence over persisted data.
30
+ // For clearOnClose drawers we always start from the empty baseline so a
31
+ // stale persistence entry from a previous lifetime can't leak in.
13
32
  const getEffectiveInitialValues = () => {
14
- // If initialValues are provided, use them
15
33
  if (initialValues && Object.keys(initialValues).length > 0) {
16
- return initialValues;
34
+ return emptyFieldValues ? { ...emptyFieldValues, ...initialValues } : initialValues;
17
35
  }
18
- // Otherwise, check for persisted data
19
- if (persistenceKey && hasPersistedData()) {
36
+ if (!clearOnClose && persistenceKey && hasPersistedData()) {
20
37
  const persistedData = restoreFormData();
21
38
  if (persistedData) {
22
39
  return persistedData;
23
40
  }
24
41
  }
25
- return initialValues || {};
42
+ return emptyFieldValues ?? initialValues ?? {};
26
43
  };
27
44
  const { control, handleSubmit, watch, setValue, clearErrors, formState: { errors, isSubmitting }, reset, getValues, } = useForm({ mode: 'onBlur', defaultValues: getEffectiveInitialValues() });
28
45
  const [pendingUpdateCount, setPendingUpdateCount] = useState(0);
@@ -39,19 +56,25 @@ const DrawerContent = ({ fields, onSubmit, isOpen, initialValues, submitButtonTe
39
56
  mountInitialValuesRef.current = initialValues || {};
40
57
  }
41
58
  wasOpenRef.current = !!isOpen;
42
- // Clear persisted data on every open → close transition when the consumer
43
- // opts in. Covers cancel, X, ESC, programmatic close, and post-submit close
44
- // all routes the user can take out of the drawer.
59
+ // Clear persisted data AND react-hook-form state on every open → close
60
+ // transition when the consumer opts in. Resetting RHF is critical: the
61
+ // watch()-driven save effect would otherwise re-populate persistence with
62
+ // the old values on the very next render (e.g. during the close animation).
45
63
  const clearOnCloseRef = useRef(clearOnClose);
46
64
  clearOnCloseRef.current = clearOnClose;
47
65
  const clearPersistedDataRef = useRef(clearPersistedData);
48
66
  clearPersistedDataRef.current = clearPersistedData;
67
+ const resetRef = useRef(reset);
68
+ resetRef.current = reset;
69
+ const emptyFieldValuesRef = useRef(emptyFieldValues);
70
+ emptyFieldValuesRef.current = emptyFieldValues;
49
71
  const previousIsOpenRef = useRef(!!isOpen);
50
72
  useEffect(() => {
51
73
  const wasOpen = previousIsOpenRef.current;
52
74
  previousIsOpenRef.current = !!isOpen;
53
75
  if (wasOpen && !isOpen && clearOnCloseRef.current) {
54
76
  clearPersistedDataRef.current();
77
+ resetRef.current(emptyFieldValuesRef.current ?? {});
55
78
  }
56
79
  }, [isOpen]);
57
80
  const password = watch('password');
@@ -74,16 +97,20 @@ const DrawerContent = ({ fields, onSubmit, isOpen, initialValues, submitButtonTe
74
97
  return true;
75
98
  });
76
99
  };
77
- // Save form data when fields change (for persistence)
100
+ // Save form data when fields change (for persistence). Guarded by `isOpen`
101
+ // so a closing drawer (whose form state hasn't been reset yet) doesn't
102
+ // re-write the values we just cleared via clearOnClose. Without this guard,
103
+ // the close-time clear races with the watch()-driven save and the save wins.
78
104
  useEffect(() => {
105
+ if (!isOpen)
106
+ return;
79
107
  if (persistenceKey && allFields && Object.keys(allFields).length > 0) {
80
- // Only save if there are actual field values (not just empty object)
81
108
  const hasValues = Object.values(allFields).some((value) => value !== undefined && value !== null && value !== '');
82
109
  if (hasValues) {
83
110
  saveFormData(allFields, true);
84
111
  }
85
112
  }
86
- }, [allFields, persistenceKey, saveFormData]);
113
+ }, [isOpen, allFields, persistenceKey, saveFormData]);
87
114
  // Process initial field updates once when drawer opens
88
115
  useEffect(() => {
89
116
  if (isOpen && !initialLoadPerformedRef.current && processInitialFieldUpdates) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pagamio/frontend-commons-lib",
3
3
  "description": "Pagamio library for Frontend reusable components like the form engine and table container",
4
- "version": "0.8.343",
4
+ "version": "0.8.345",
5
5
  "publishConfig": {
6
6
  "access": "public",
7
7
  "provenance": false