@chris-c-brine/form-dialog 1.1.7 → 1.1.8
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/components/buttons/LoadingButton.d.ts +1 -1
- package/dist/components/dialogs/FormDialog.d.ts +1 -1
- package/dist/components/forms/PaperForm.d.ts +1 -1
- package/dist/components/index.d.ts +0 -1
- package/dist/hooks/index.d.ts +0 -2
- package/dist/hooks/useMaxAttempts.d.ts +11 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.esm.js +154 -343
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +154 -343
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +26 -43
- package/dist/utils/applyDefaultFormDialogProps.d.ts +5 -2
- package/dist/utils/index.d.ts +0 -1
- package/package.json +10 -13
|
@@ -38,4 +38,4 @@ import { LoadingButtonProps } from "../../types";
|
|
|
38
38
|
* Process Payment
|
|
39
39
|
* </LoadingButton>
|
|
40
40
|
*/
|
|
41
|
-
export declare const LoadingButton: ({ children, loading, altIcon, ...props }: LoadingButtonProps) => import("react/jsx-runtime").JSX.Element;
|
|
41
|
+
export declare const LoadingButton: ({ children, loading, altIcon, loadingIconProps, ...props }: LoadingButtonProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -22,6 +22,6 @@ import { FormDialogProps } from "../../types";
|
|
|
22
22
|
*
|
|
23
23
|
*/
|
|
24
24
|
export declare const FormDialog: {
|
|
25
|
-
<T extends FieldValues>({ formProps, children, open, onClose,
|
|
25
|
+
<T extends FieldValues>({ formProps, children, open, onClose, ...dialogProps }: FormDialogProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
26
26
|
displayName: string;
|
|
27
27
|
};
|
|
@@ -46,4 +46,4 @@ import { PaperFormProps } from "../../types";
|
|
|
46
46
|
*
|
|
47
47
|
* @template T - The type of form values being handled
|
|
48
48
|
*/
|
|
49
|
-
export declare const PaperForm: <T extends FieldValues>({ children,
|
|
49
|
+
export declare const PaperForm: <T extends FieldValues>({ children, formProps, ...paperProps }: PaperFormProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -2,7 +2,6 @@ export * from "./dialogs/FormDialog";
|
|
|
2
2
|
export * from "./dialogs/BaseDialog";
|
|
3
3
|
export * from "./dialogs/BlackoutDialog";
|
|
4
4
|
export * from "./forms/PaperForm";
|
|
5
|
-
export * from "./forms/PersistForm";
|
|
6
5
|
export * from "./buttons/FormCancelButton";
|
|
7
6
|
export * from "./buttons/FormSubmitButton";
|
|
8
7
|
export * from "./buttons/FormResetButton";
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -1,2 +1,13 @@
|
|
|
1
1
|
import { UseMaxAttemptProps } from "../types";
|
|
2
|
+
/**
|
|
3
|
+
* Hook that monitors form submission attempts and disables the form when a limit is reached.
|
|
4
|
+
*
|
|
5
|
+
* It performs two main functions:
|
|
6
|
+
* 1. Monitors `formState.submitCount` and calls `setDisabled(true)` from the dialog context
|
|
7
|
+
* once it reaches or exceeds the specified `maxAttempts`.
|
|
8
|
+
* 2. When the dialog context enters a `disabled` state, it automatically resets form fields
|
|
9
|
+
* that have errors or are dirty to ensure a clean state for the user.
|
|
10
|
+
*
|
|
11
|
+
* @param props - UseMaxAttemptProps
|
|
12
|
+
*/
|
|
2
13
|
export declare const useMaxAttempts: ({ maxAttempts }: UseMaxAttemptProps) => void;
|
package/dist/index.d.ts
CHANGED
package/dist/index.esm.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment as Fragment$1 } from 'react/jsx-runtime';
|
|
2
|
-
import { createContext,
|
|
3
|
-
import { Dialog, DialogTitle, DialogContent, DialogActions, Paper, IconButton, Button,
|
|
4
|
-
import {
|
|
2
|
+
import { createContext, Fragment, useState, useEffect, useCallback, useMemo, useContext, useRef, memo } from 'react';
|
|
3
|
+
import { Dialog, DialogTitle, DialogContent, DialogActions, Paper, IconButton, Button, Box, CircularProgress, Badge, Grid } from '@mui/material';
|
|
4
|
+
import { FormContainer, useFormContext, useFormState } from 'react-hook-form-mui';
|
|
5
5
|
import { Refresh, Close, Save } from '@mui/icons-material';
|
|
6
6
|
import { useTheme } from '@mui/material/styles';
|
|
7
|
-
import { create } from 'zustand';
|
|
8
|
-
import { createJSONStorage, persist } from 'zustand/middleware';
|
|
9
7
|
|
|
10
8
|
/**
|
|
11
9
|
* A component for rendering a modal dialog with an optional blackout effect.
|
|
@@ -63,45 +61,56 @@ const BlackoutDialog = ({ open = false, blackout = false, id = "blackout-dialog"
|
|
|
63
61
|
*/
|
|
64
62
|
const BaseDialog = ({ title = null, closeButton, titleProps, children = null, contentProps, id, actions = null, actionsProps, ...props }) => (jsxs(BlackoutDialog, { id: id, ...props, children: [title && jsx(DialogTitle, { ...titleProps, children: title }), " ", closeButton, children && jsx(DialogContent, { ...contentProps, children: children }), actions && jsx(DialogActions, { ...actionsProps, children: actions })] }));
|
|
65
63
|
|
|
66
|
-
const FormDialogContext = createContext(undefined);
|
|
67
|
-
FormDialogContext.displayName = "FormDialogContext";
|
|
68
|
-
|
|
69
|
-
// src/components/dialogs/FormDialog/hooks/useFormDialog.ts
|
|
70
64
|
/**
|
|
71
|
-
*
|
|
65
|
+
* A component that combines a Material UI Paper with a form container
|
|
72
66
|
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
67
|
+
* PaperForm wraps form content in an elevated paper surface, providing
|
|
68
|
+
* visual distinction and a clean container for form elements. It integrates
|
|
69
|
+
* seamlessly with react-hook-form by using FormContainer internally.
|
|
76
70
|
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
* - Form disabled state and setter function
|
|
71
|
+
* This component is useful for creating standalone form surfaces outside of dialogs,
|
|
72
|
+
* such as on pages or within cards. It supports all Paper props for styling
|
|
73
|
+
* while handling form state management through FormContainer.
|
|
81
74
|
*
|
|
82
|
-
* @
|
|
75
|
+
* @example
|
|
76
|
+
* // Basic usage
|
|
77
|
+
* <PaperForm
|
|
78
|
+
* formProps={{
|
|
79
|
+
* defaultValues: { name: "", email: "" },
|
|
80
|
+
* onSuccess: handleSubmit
|
|
81
|
+
* }}
|
|
82
|
+
* elevation={3}
|
|
83
|
+
* >
|
|
84
|
+
* <TextFieldElement name="name" label="Name" />
|
|
85
|
+
* <TextFieldElement name="email" label="Email" />
|
|
86
|
+
* <Button type="submit">Submit</Button>
|
|
87
|
+
* </PaperForm>
|
|
83
88
|
*
|
|
84
89
|
* @example
|
|
85
|
-
* //
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
90
|
+
* // With custom styling and validation
|
|
91
|
+
* <PaperForm
|
|
92
|
+
* formProps={{
|
|
93
|
+
* defaultValues: formDefaultValues,
|
|
94
|
+
* onSuccess: handleSubmit,
|
|
95
|
+
* onError: handleError,
|
|
96
|
+
* }}
|
|
97
|
+
* sx={{
|
|
98
|
+
* padding: 3,
|
|
99
|
+
* borderRadius: 2,
|
|
100
|
+
* backgroundColor: 'background.paper',
|
|
101
|
+
* }}
|
|
102
|
+
* elevation={2}
|
|
103
|
+
* >
|
|
104
|
+
* <FormFields />
|
|
105
|
+
* <FormDialogActions submitProps={{ children: "Save Profile" }} />
|
|
106
|
+
* </PaperForm>
|
|
95
107
|
*
|
|
96
|
-
* @
|
|
108
|
+
* @template T - The type of form values being handled
|
|
97
109
|
*/
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}
|
|
103
|
-
return context;
|
|
104
|
-
};
|
|
110
|
+
const PaperForm = ({ children, formProps, ...paperProps }) => (jsx(Paper, { ...paperProps, children: jsx(FormContainer, { ...formProps, children: children }) }));
|
|
111
|
+
|
|
112
|
+
const FormDialogContext = createContext(undefined);
|
|
113
|
+
FormDialogContext.displayName = "FormDialogContext";
|
|
105
114
|
|
|
106
115
|
const hasMaxAttempts = (maxAttempts) => {
|
|
107
116
|
return !!maxAttempts && isFinite(maxAttempts);
|
|
@@ -17321,37 +17330,6 @@ function requireLodash () {
|
|
|
17321
17330
|
|
|
17322
17331
|
var lodashExports = requireLodash();
|
|
17323
17332
|
|
|
17324
|
-
/**
|
|
17325
|
-
* Compares two objects for deep equality.
|
|
17326
|
-
*
|
|
17327
|
-
* This function uses lodash's `isEqualWith` function for deep comparison,
|
|
17328
|
-
* with additional logic for handling numbers and empty values.
|
|
17329
|
-
*
|
|
17330
|
-
* @param a The first object to compare.
|
|
17331
|
-
* @param b The second object to compare.
|
|
17332
|
-
* @param equalEmpty (default: false) Whether to consider empty values (null, undefined, empty arrays or objects) equal.
|
|
17333
|
-
* @returns True if the objects are deeply equal, false otherwise.
|
|
17334
|
-
*/
|
|
17335
|
-
const deepCompare = (a, b, equalEmpty = false) => {
|
|
17336
|
-
return lodashExports.isEqualWith(a, b, (objA, objB) => {
|
|
17337
|
-
if (lodashExports.isObject(objA) || lodashExports.isObject(objB))
|
|
17338
|
-
return undefined; // Delegate to lodash for object comparison
|
|
17339
|
-
if (lodashExports.isNumber(objA) || lodashExports.isNumber(objB)) {
|
|
17340
|
-
/*
|
|
17341
|
-
console.log(_.isEmpty(123456));
|
|
17342
|
-
this returns true, should be false
|
|
17343
|
-
|
|
17344
|
-
Source: https://github.com/lodash/lodash/issues/496
|
|
17345
|
-
*/
|
|
17346
|
-
return equalEmpty ? Number(objA) === Number(objB) : lodashExports.isEqual(objA, objB);
|
|
17347
|
-
}
|
|
17348
|
-
if (equalEmpty && lodashExports.isEmpty(objA) && lodashExports.isEmpty(objB))
|
|
17349
|
-
return true;
|
|
17350
|
-
return lodashExports.isEqual(objA, objB);
|
|
17351
|
-
});
|
|
17352
|
-
};
|
|
17353
|
-
deepCompare.displayName = "deepCompare";
|
|
17354
|
-
|
|
17355
17333
|
function applyDefaultFormDialogProps({ resetProps, submitProps, gridProps, cancelProps, variant = "iconText" }) {
|
|
17356
17334
|
// Max Attempts
|
|
17357
17335
|
const maxAttempts = (submitProps === null || submitProps === void 0 ? void 0 : submitProps.maxAttempts) || Infinity;
|
|
@@ -17413,272 +17391,6 @@ const ThemeBridge = ({ children }) => {
|
|
|
17413
17391
|
return (jsx(ParentThemeContext.Provider, { value: themeSnapshot, children: children }));
|
|
17414
17392
|
};
|
|
17415
17393
|
|
|
17416
|
-
const useMaxAttempts = ({ maxAttempts }) => {
|
|
17417
|
-
const { formState, resetField } = useFormContext();
|
|
17418
|
-
const { setDisabled, disabled } = useFormDialog();
|
|
17419
|
-
const hasRun = useRef(false);
|
|
17420
|
-
// Reset & disable the form when the count exceeds the maxAttempts
|
|
17421
|
-
useEffect(() => {
|
|
17422
|
-
if (hasMaxAttempts(maxAttempts) && formState.submitCount >= maxAttempts && !hasRun.current) {
|
|
17423
|
-
setDisabled(true);
|
|
17424
|
-
hasRun.current = true;
|
|
17425
|
-
}
|
|
17426
|
-
}, [formState.submitCount, maxAttempts, setDisabled]);
|
|
17427
|
-
// Debugging & disabled form field reset
|
|
17428
|
-
useEffect(() => {
|
|
17429
|
-
if (disabled) {
|
|
17430
|
-
Object.keys(lodashExports.merge(formState.dirtyFields, formState.errors)).forEach((i) => {
|
|
17431
|
-
resetField(i, { keepTouched: true });
|
|
17432
|
-
});
|
|
17433
|
-
}
|
|
17434
|
-
}, [disabled, formState, maxAttempts, resetField]);
|
|
17435
|
-
};
|
|
17436
|
-
|
|
17437
|
-
// src/state/createFormChangeStore.ts
|
|
17438
|
-
const storage = createJSONStorage(() => {
|
|
17439
|
-
try {
|
|
17440
|
-
return sessionStorage;
|
|
17441
|
-
}
|
|
17442
|
-
catch (e) {
|
|
17443
|
-
return localStorage;
|
|
17444
|
-
}
|
|
17445
|
-
});
|
|
17446
|
-
/**
|
|
17447
|
-
* Factory function to create a form store with a custom storage name.
|
|
17448
|
-
*
|
|
17449
|
-
* @param storeName - Unique name for sessionStorage/localStorage key.
|
|
17450
|
-
* @returns Zustand store with form data.
|
|
17451
|
-
*/
|
|
17452
|
-
const createFormChangeStore = (storeName) => create()(persist((set) => ({
|
|
17453
|
-
formData: {},
|
|
17454
|
-
updateFormData: (key, value) => {
|
|
17455
|
-
return set((state) => ({
|
|
17456
|
-
formData: { ...state.formData, [key]: value },
|
|
17457
|
-
}));
|
|
17458
|
-
},
|
|
17459
|
-
resetFormData: (key) => {
|
|
17460
|
-
return set((state) => {
|
|
17461
|
-
if (key) {
|
|
17462
|
-
/* eslint-disable-next-line @typescript-eslint/no-unused-vars */
|
|
17463
|
-
const { [key]: _, ...remaining } = state.formData;
|
|
17464
|
-
return { formData: remaining };
|
|
17465
|
-
}
|
|
17466
|
-
return { formData: {} };
|
|
17467
|
-
});
|
|
17468
|
-
},
|
|
17469
|
-
}), {
|
|
17470
|
-
storage: storage,
|
|
17471
|
-
name: storeName, // Key for sessionStorage
|
|
17472
|
-
}));
|
|
17473
|
-
|
|
17474
|
-
// src/hooks/useOnMount.ts
|
|
17475
|
-
/**
|
|
17476
|
-
* Runs a provided callback function once on the first component mount.
|
|
17477
|
-
*
|
|
17478
|
-
* @param callback - The function to run on first mount.
|
|
17479
|
-
*/
|
|
17480
|
-
function useOnMount(callback) {
|
|
17481
|
-
const hasMounted = useRef(false);
|
|
17482
|
-
useEffect(() => {
|
|
17483
|
-
if (!hasMounted.current) {
|
|
17484
|
-
callback();
|
|
17485
|
-
hasMounted.current = true;
|
|
17486
|
-
}
|
|
17487
|
-
// Cleanup to prevent callback logic from running on unmount
|
|
17488
|
-
return () => {
|
|
17489
|
-
hasMounted.current = true;
|
|
17490
|
-
};
|
|
17491
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
17492
|
-
}, []);
|
|
17493
|
-
}
|
|
17494
|
-
|
|
17495
|
-
// src/state/FormStoreProvider.tsx
|
|
17496
|
-
/**
|
|
17497
|
-
* Hook that enables form state persistence across sessions
|
|
17498
|
-
*
|
|
17499
|
-
* This hook connects a form to persistent storage (e.g., sessionStorage)
|
|
17500
|
-
* allowing form values to be preserved when navigating away and returning.
|
|
17501
|
-
* It works by watching form changes and syncing with a zustand store.
|
|
17502
|
-
*
|
|
17503
|
-
* Key features:
|
|
17504
|
-
* - Persists form values during navigation or page reloads
|
|
17505
|
-
* - Automatically restores saved values when form is rendered
|
|
17506
|
-
* - Debounced updates to avoid excessive storage operations
|
|
17507
|
-
* - Only saves changed fields, not the entire form state
|
|
17508
|
-
* - Automatically clears storage when form values match defaults
|
|
17509
|
-
*
|
|
17510
|
-
*/
|
|
17511
|
-
const usePersistForm = ({ formName = "", formContext }) => {
|
|
17512
|
-
// const { setValue, watch, formState } = formContext;
|
|
17513
|
-
const { formData, updateFormData, resetFormData } = createFormChangeStore(formName)();
|
|
17514
|
-
const { disabled } = useFormDialog();
|
|
17515
|
-
const debouncedUpdate = lodashExports.debounce((key, values) => {
|
|
17516
|
-
updateFormData(key, values);
|
|
17517
|
-
}, 200);
|
|
17518
|
-
useEffect(() => {
|
|
17519
|
-
if (!formName || !formContext)
|
|
17520
|
-
return;
|
|
17521
|
-
const { watch, formState } = formContext;
|
|
17522
|
-
const subscription = watch((newValues, { name }) => {
|
|
17523
|
-
if (deepCompare(newValues, formState.defaultValues, true)) {
|
|
17524
|
-
resetFormData();
|
|
17525
|
-
}
|
|
17526
|
-
else if (name) {
|
|
17527
|
-
const newValue = newValues[name];
|
|
17528
|
-
const currentValue = formData[name];
|
|
17529
|
-
// Allow clearing fields
|
|
17530
|
-
if (currentValue !== newValue) {
|
|
17531
|
-
debouncedUpdate(name, newValue);
|
|
17532
|
-
}
|
|
17533
|
-
}
|
|
17534
|
-
});
|
|
17535
|
-
return () => {
|
|
17536
|
-
subscription.unsubscribe();
|
|
17537
|
-
debouncedUpdate.cancel();
|
|
17538
|
-
};
|
|
17539
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
17540
|
-
}, [formContext, debouncedUpdate]);
|
|
17541
|
-
useOnMount(() => {
|
|
17542
|
-
if (!lodashExports.isEmpty(formData) && !disabled && !(formContext === null || formContext === void 0 ? void 0 : formContext.formState.isLoading) && formName) {
|
|
17543
|
-
setTimeout(() => {
|
|
17544
|
-
Object.entries(formData).forEach(([key, value]) => {
|
|
17545
|
-
formContext === null || formContext === void 0 ? void 0 : formContext.setValue(key, value, { shouldDirty: true, shouldTouch: true });
|
|
17546
|
-
});
|
|
17547
|
-
}, 200);
|
|
17548
|
-
}
|
|
17549
|
-
});
|
|
17550
|
-
};
|
|
17551
|
-
|
|
17552
|
-
/**
|
|
17553
|
-
* Hook for managing dialog state and providing dialog control functions
|
|
17554
|
-
*
|
|
17555
|
-
* This hook provides a simple way to manage the dialog state and returns
|
|
17556
|
-
* functions to open and close the dialog, along with props that can be
|
|
17557
|
-
* spread onto a Material-UI Dialog component.
|
|
17558
|
-
*
|
|
17559
|
-
* Restores focus to the opening element, but only after the dialog has fully closed.
|
|
17560
|
-
*
|
|
17561
|
-
* @example
|
|
17562
|
-
* // Basic usage
|
|
17563
|
-
* const { openDialog, closeDialog, dialogProps } = useDialog();
|
|
17564
|
-
* return (<>
|
|
17565
|
-
* <Button onClick={openDialog}>Open Dialog</Button>
|
|
17566
|
-
* <BaseDialog {...dialogProps}>Dialog Content</BaseDialog>
|
|
17567
|
-
* </>);
|
|
17568
|
-
*
|
|
17569
|
-
* @example
|
|
17570
|
-
* // With initial configuration
|
|
17571
|
-
* const { dialogProps } = useDialog({ keepMounted: true});
|
|
17572
|
-
*
|
|
17573
|
-
* @param props - Optional configuration options
|
|
17574
|
-
*/
|
|
17575
|
-
const useDialog = (props) => {
|
|
17576
|
-
const [open, setOpen] = useState(!!(props === null || props === void 0 ? void 0 : props.open));
|
|
17577
|
-
const closeDialog = useCallback(() => setOpen(false), []);
|
|
17578
|
-
const openDialog = useCallback(() => setOpen(true), []);
|
|
17579
|
-
return {
|
|
17580
|
-
closeDialog,
|
|
17581
|
-
openDialog,
|
|
17582
|
-
dialogProps: { open, onClose: closeDialog, keepMounted: !!(props === null || props === void 0 ? void 0 : props.keepMounted) }
|
|
17583
|
-
};
|
|
17584
|
-
};
|
|
17585
|
-
|
|
17586
|
-
/**
|
|
17587
|
-
* A component that enables form state persistence across sessions
|
|
17588
|
-
*
|
|
17589
|
-
* PersistForm is a lightweight wrapper that connects a form to persistent storage,
|
|
17590
|
-
* allowing form values to be preserved when navigating away and returning. It wraps
|
|
17591
|
-
* the usePersistedForm hook in a convenient component API.
|
|
17592
|
-
*
|
|
17593
|
-
* Key features:
|
|
17594
|
-
* - Persists form values during navigation or page reloads
|
|
17595
|
-
* - Automatically restores saved values when the form is rendered
|
|
17596
|
-
* - Only saves changed fields, not the entire form state
|
|
17597
|
-
* - Automatically clears storage when form values match defaults
|
|
17598
|
-
* - Works with any React Hook Form based forms
|
|
17599
|
-
*
|
|
17600
|
-
* Note: This component must be used inside a FormProvider from react-hook-form
|
|
17601
|
-
* and should be within a FormDialogProvider for full functionality.
|
|
17602
|
-
*
|
|
17603
|
-
* @example
|
|
17604
|
-
* // Basic usage
|
|
17605
|
-
* const MyForm = () => {
|
|
17606
|
-
* const methods = useForm({ defaultValues: { name: '' } });
|
|
17607
|
-
*
|
|
17608
|
-
* return (<FormProvider {...methods}>
|
|
17609
|
-
* <PersistForm formName="user-profile">
|
|
17610
|
-
* <TextFieldElement name="name" label="Name" />
|
|
17611
|
-
* <FormSubmitButton>Save</FormSubmitButton>
|
|
17612
|
-
* </PersistForm>
|
|
17613
|
-
* </FormProvider>);
|
|
17614
|
-
* }
|
|
17615
|
-
*
|
|
17616
|
-
* @example
|
|
17617
|
-
* // Usage within a dialog
|
|
17618
|
-
* <FormDialog
|
|
17619
|
-
* formProps={{ defaultValues: defaultValues }}
|
|
17620
|
-
* title="Edit Profile"
|
|
17621
|
-
* >
|
|
17622
|
-
* <PersistForm formName="edit-profile-dialog">
|
|
17623
|
-
* <ProfileFormFields />
|
|
17624
|
-
* </PersistForm>
|
|
17625
|
-
* </FormDialog>
|
|
17626
|
-
*/
|
|
17627
|
-
const PersistForm = memo(function ({ children, formName }) {
|
|
17628
|
-
const formContext = useFormContext();
|
|
17629
|
-
usePersistForm({ formName, formContext });
|
|
17630
|
-
return jsx(Fragment$1, { children: children });
|
|
17631
|
-
});
|
|
17632
|
-
PersistForm.displayName = "PersistForm";
|
|
17633
|
-
|
|
17634
|
-
/**
|
|
17635
|
-
* A component that combines a Material UI Paper with a form container
|
|
17636
|
-
*
|
|
17637
|
-
* PaperForm wraps form content in an elevated paper surface, providing
|
|
17638
|
-
* visual distinction and a clean container for form elements. It integrates
|
|
17639
|
-
* seamlessly with react-hook-form by using FormContainer internally.
|
|
17640
|
-
*
|
|
17641
|
-
* This component is useful for creating standalone form surfaces outside of dialogs,
|
|
17642
|
-
* such as on pages or within cards. It supports all Paper props for styling
|
|
17643
|
-
* while handling form state management through FormContainer.
|
|
17644
|
-
*
|
|
17645
|
-
* @example
|
|
17646
|
-
* // Basic usage
|
|
17647
|
-
* <PaperForm
|
|
17648
|
-
* formProps={{
|
|
17649
|
-
* defaultValues: { name: "", email: "" },
|
|
17650
|
-
* onSuccess: handleSubmit
|
|
17651
|
-
* }}
|
|
17652
|
-
* elevation={3}
|
|
17653
|
-
* >
|
|
17654
|
-
* <TextFieldElement name="name" label="Name" />
|
|
17655
|
-
* <TextFieldElement name="email" label="Email" />
|
|
17656
|
-
* <Button type="submit">Submit</Button>
|
|
17657
|
-
* </PaperForm>
|
|
17658
|
-
*
|
|
17659
|
-
* @example
|
|
17660
|
-
* // With custom styling and validation
|
|
17661
|
-
* <PaperForm
|
|
17662
|
-
* formProps={{
|
|
17663
|
-
* defaultValues: formDefaultValues,
|
|
17664
|
-
* onSuccess: handleSubmit,
|
|
17665
|
-
* onError: handleError,
|
|
17666
|
-
* }}
|
|
17667
|
-
* sx={{
|
|
17668
|
-
* padding: 3,
|
|
17669
|
-
* borderRadius: 2,
|
|
17670
|
-
* backgroundColor: 'background.paper',
|
|
17671
|
-
* }}
|
|
17672
|
-
* elevation={2}
|
|
17673
|
-
* >
|
|
17674
|
-
* <FormFields />
|
|
17675
|
-
* <FormDialogActions submitProps={{ children: "Save Profile" }} />
|
|
17676
|
-
* </PaperForm>
|
|
17677
|
-
*
|
|
17678
|
-
* @template T - The type of form values being handled
|
|
17679
|
-
*/
|
|
17680
|
-
const PaperForm = ({ children, persistKey = "", formProps, ...paperProps }) => (jsx(Paper, { ...paperProps, children: jsx(FormContainer, { ...formProps, children: jsx(PersistForm, { formName: persistKey, children: children }) }) }));
|
|
17681
|
-
|
|
17682
17394
|
/**
|
|
17683
17395
|
* Context provider component for form dialog state management
|
|
17684
17396
|
*
|
|
@@ -17740,8 +17452,8 @@ const FormDialogProvider = ({ children, ...value }) => {
|
|
|
17740
17452
|
* - useFormDialog() - Access dialog controls and state
|
|
17741
17453
|
*
|
|
17742
17454
|
*/
|
|
17743
|
-
const FormDialog = function ({ formProps, children, open, onClose,
|
|
17744
|
-
const PaperComponent = useCallback((props) => jsx(PaperForm, {
|
|
17455
|
+
const FormDialog = function ({ formProps, children, open, onClose, ...dialogProps }) {
|
|
17456
|
+
const PaperComponent = useCallback((props) => jsx(PaperForm, { formProps: formProps, ...props }), [formProps]);
|
|
17745
17457
|
const baseDialogProps = useMemo(() => lodashExports.merge({
|
|
17746
17458
|
actionsProps: { sx: { pt: 2.5 } },
|
|
17747
17459
|
contentProps: {
|
|
@@ -17761,6 +17473,109 @@ const FormDialog = function ({ formProps, children, open, onClose, persistKey =
|
|
|
17761
17473
|
};
|
|
17762
17474
|
FormDialog.displayName = "FormDialog";
|
|
17763
17475
|
|
|
17476
|
+
// src/components/dialogs/FormDialog/hooks/useFormDialog.ts
|
|
17477
|
+
/**
|
|
17478
|
+
* Hook for accessing the FormDialog context values and functions
|
|
17479
|
+
*
|
|
17480
|
+
* This hook provides access to the form dialog state and controls managed by
|
|
17481
|
+
* the FormDialogProvider. It allows components to interact with the dialog state,
|
|
17482
|
+
* including open/close status and form-wide disabled state.
|
|
17483
|
+
*
|
|
17484
|
+
* The context provides:
|
|
17485
|
+
* - Dialog open state
|
|
17486
|
+
* - Close dialog function
|
|
17487
|
+
* - Form disabled state and setter function
|
|
17488
|
+
*
|
|
17489
|
+
* @throws Error if used outside a FormDialogProvider
|
|
17490
|
+
*
|
|
17491
|
+
* @example
|
|
17492
|
+
* // Using in a form button component
|
|
17493
|
+
* const FormButton = () => {
|
|
17494
|
+
* const { openDialog, disabled } = useFormDialog();
|
|
17495
|
+
* return (<Button
|
|
17496
|
+
* disabled={disabled}
|
|
17497
|
+
* onClick={() => openDialog()}
|
|
17498
|
+
* >
|
|
17499
|
+
* Cancel
|
|
17500
|
+
* </Button>);
|
|
17501
|
+
* }
|
|
17502
|
+
*
|
|
17503
|
+
* @returns FormDialogContextType object containing dialog state and controls
|
|
17504
|
+
*/
|
|
17505
|
+
const useFormDialog = () => {
|
|
17506
|
+
const context = useContext(FormDialogContext);
|
|
17507
|
+
if (!context) {
|
|
17508
|
+
throw new Error("useFormDialog must be used within a FormDialogProvider");
|
|
17509
|
+
}
|
|
17510
|
+
return context;
|
|
17511
|
+
};
|
|
17512
|
+
|
|
17513
|
+
/**
|
|
17514
|
+
* Hook that monitors form submission attempts and disables the form when a limit is reached.
|
|
17515
|
+
*
|
|
17516
|
+
* It performs two main functions:
|
|
17517
|
+
* 1. Monitors `formState.submitCount` and calls `setDisabled(true)` from the dialog context
|
|
17518
|
+
* once it reaches or exceeds the specified `maxAttempts`.
|
|
17519
|
+
* 2. When the dialog context enters a `disabled` state, it automatically resets form fields
|
|
17520
|
+
* that have errors or are dirty to ensure a clean state for the user.
|
|
17521
|
+
*
|
|
17522
|
+
* @param props - UseMaxAttemptProps
|
|
17523
|
+
*/
|
|
17524
|
+
const useMaxAttempts = ({ maxAttempts }) => {
|
|
17525
|
+
const { formState, resetField } = useFormContext();
|
|
17526
|
+
const { setDisabled, disabled } = useFormDialog();
|
|
17527
|
+
const hasRun = useRef(false);
|
|
17528
|
+
// Reset & disable the form when the count exceeds the maxAttempts
|
|
17529
|
+
useEffect(() => {
|
|
17530
|
+
if (hasMaxAttempts(maxAttempts) && formState.submitCount >= maxAttempts && !hasRun.current) {
|
|
17531
|
+
setDisabled(true);
|
|
17532
|
+
hasRun.current = true;
|
|
17533
|
+
}
|
|
17534
|
+
}, [formState.submitCount, maxAttempts, setDisabled]);
|
|
17535
|
+
// Debugging & disabled form field reset
|
|
17536
|
+
useEffect(() => {
|
|
17537
|
+
if (disabled) {
|
|
17538
|
+
Object.keys(lodashExports.merge(formState.dirtyFields, formState.errors)).forEach((i) => {
|
|
17539
|
+
resetField(i, { keepTouched: true });
|
|
17540
|
+
});
|
|
17541
|
+
}
|
|
17542
|
+
}, [disabled, formState, maxAttempts, resetField]);
|
|
17543
|
+
};
|
|
17544
|
+
|
|
17545
|
+
/**
|
|
17546
|
+
* Hook for managing dialog state and providing dialog control functions
|
|
17547
|
+
*
|
|
17548
|
+
* This hook provides a simple way to manage the dialog state and returns
|
|
17549
|
+
* functions to open and close the dialog, along with props that can be
|
|
17550
|
+
* spread onto a Material-UI Dialog component.
|
|
17551
|
+
*
|
|
17552
|
+
* Restores focus to the opening element, but only after the dialog has fully closed.
|
|
17553
|
+
*
|
|
17554
|
+
* @example
|
|
17555
|
+
* // Basic usage
|
|
17556
|
+
* const { openDialog, closeDialog, dialogProps } = useDialog();
|
|
17557
|
+
* return (<>
|
|
17558
|
+
* <Button onClick={openDialog}>Open Dialog</Button>
|
|
17559
|
+
* <BaseDialog {...dialogProps}>Dialog Content</BaseDialog>
|
|
17560
|
+
* </>);
|
|
17561
|
+
*
|
|
17562
|
+
* @example
|
|
17563
|
+
* // With initial configuration
|
|
17564
|
+
* const { dialogProps } = useDialog({ keepMounted: true});
|
|
17565
|
+
*
|
|
17566
|
+
* @param props - Optional configuration options
|
|
17567
|
+
*/
|
|
17568
|
+
const useDialog = (props) => {
|
|
17569
|
+
const [open, setOpen] = useState(!!(props === null || props === void 0 ? void 0 : props.open));
|
|
17570
|
+
const closeDialog = useCallback(() => setOpen(false), []);
|
|
17571
|
+
const openDialog = useCallback(() => setOpen(true), []);
|
|
17572
|
+
return {
|
|
17573
|
+
closeDialog,
|
|
17574
|
+
openDialog,
|
|
17575
|
+
dialogProps: { open, onClose: closeDialog, keepMounted: !!(props === null || props === void 0 ? void 0 : props.keepMounted) }
|
|
17576
|
+
};
|
|
17577
|
+
};
|
|
17578
|
+
|
|
17764
17579
|
/**
|
|
17765
17580
|
* A cancel button component that integrates with FormDialogContext.
|
|
17766
17581
|
* Automatically closes the parent dialog when clicked.
|
|
@@ -17829,8 +17644,7 @@ FormCancelButton.displayName = "FormCancelButton";
|
|
|
17829
17644
|
* Process Payment
|
|
17830
17645
|
* </LoadingButton>
|
|
17831
17646
|
*/
|
|
17832
|
-
const LoadingButton = ({ children, loading = false, altIcon, ...props }) => {
|
|
17833
|
-
const theme = useTheme$1();
|
|
17647
|
+
const LoadingButton = ({ children, loading = false, altIcon, loadingIconProps, ...props }) => {
|
|
17834
17648
|
return (jsxs(Button, { ...props, children: [!loading ? altIcon : (jsx(Box, { sx: {
|
|
17835
17649
|
display: "flex",
|
|
17836
17650
|
alignItems: "center",
|
|
@@ -17838,7 +17652,7 @@ const LoadingButton = ({ children, loading = false, altIcon, ...props }) => {
|
|
|
17838
17652
|
width: "100%",
|
|
17839
17653
|
height: "auto",
|
|
17840
17654
|
mr: 1,
|
|
17841
|
-
}, children: jsx(CircularProgress, {
|
|
17655
|
+
}, children: jsx(CircularProgress, { ...loadingIconProps }) })), children] }));
|
|
17842
17656
|
};
|
|
17843
17657
|
|
|
17844
17658
|
/**
|
|
@@ -17916,16 +17730,13 @@ FormSubmitButton.displayName = "FormSubmitButton";
|
|
|
17916
17730
|
const FormResetButton = memo(function (props) {
|
|
17917
17731
|
var _a;
|
|
17918
17732
|
const formKey = (_a = props === null || props === void 0 ? void 0 : props.formKey) !== null && _a !== void 0 ? _a : "";
|
|
17919
|
-
const { resetFormData } = createFormChangeStore(formKey)();
|
|
17920
17733
|
const { reset } = useFormContext();
|
|
17921
17734
|
const { isSubmitting, isLoading, isDirty } = useFormState();
|
|
17922
17735
|
const { disabled: disabledForm } = useFormDialog();
|
|
17923
17736
|
const keepSubmitCount = !!(props === null || props === void 0 ? void 0 : props.keepCount);
|
|
17924
17737
|
const handleOnClick = useCallback(() => {
|
|
17925
17738
|
reset(undefined, { keepSubmitCount, keepIsSubmitted: keepSubmitCount });
|
|
17926
|
-
|
|
17927
|
-
resetFormData();
|
|
17928
|
-
}, [keepSubmitCount, formKey, reset, resetFormData]);
|
|
17739
|
+
}, [keepSubmitCount, formKey, reset]);
|
|
17929
17740
|
const isBusy = isSubmitting || isLoading;
|
|
17930
17741
|
const isDisabled = (props === null || props === void 0 ? void 0 : props.disabled) || disabledForm;
|
|
17931
17742
|
const isClean = !isDirty;
|
|
@@ -18028,5 +17839,5 @@ const FormDialogActions = ({ resetProps, submitProps, cancelProps, children, var
|
|
|
18028
17839
|
return (jsxs(Grid, { container: true, ...gridContainerProps, children: [!removeCancelButton && jsx(Grid, { children: jsx(FormCancelButton, { ...cancelButtonProps }) }), !removeResetButton && jsx(Grid, { children: jsx(FormResetButton, { ...resetButtonProps }) }), children !== null && children !== void 0 ? children : jsx(GridSpacer, {}), jsx(Grid, { children: jsx(FormSubmitButton, { ...submitButtonProps }) })] }));
|
|
18029
17840
|
};
|
|
18030
17841
|
|
|
18031
|
-
export { BaseDialog, BlackoutDialog, FormCancelButton, FormDialog, FormDialogActions, FormDialogProvider, FormResetButton, FormSubmitButton, GridSpacer, LoadingButton, PaperForm,
|
|
17842
|
+
export { BaseDialog, BlackoutDialog, FormCancelButton, FormDialog, FormDialogActions, FormDialogProvider, FormResetButton, FormSubmitButton, GridSpacer, LoadingButton, PaperForm, useDialog, useFormDialog };
|
|
18032
17843
|
//# sourceMappingURL=index.esm.js.map
|