@appbuckets/react-ui-forms
Version:
An utilities package to manage and create Form using AppBuckets ReactUI
332 lines (329 loc) • 9.97 kB
JavaScript
import {
__rest,
__awaiter,
__read,
__assign,
__generator,
} from '../_virtual/_tslib.js';
import * as React from 'react';
import clsx from 'clsx';
import { useForm } from 'react-hook-form';
import Form from '@appbuckets/react-ui/Form';
import { HookedFormProvider } from '../context/HookedForm.context.js';
import HookedFormActions from './HookedFormActions.js';
import HookedFormContent from './HookedFormContent.js';
var HookedForm = React.forwardRef(function (props, ref) {
// ----
// Deconstruct Options
// ----
var /** Hook form props */
autoFocusFirstError = props.autoFocusFirstError,
breakOnFirstError = props.breakOnFirstError,
context = props.context,
defaultValues = props.defaultValues,
resolver = props.resolver,
reValidateOn = props.reValidateOn,
validateOn = props.validateOn,
/** Strict props */
actionsWrapper = props.actionsWrapper,
cancelButton = props.cancelButton,
children = props.children,
className = props.className,
contentWrapper = props.contentWrapper,
disabled = props.disabled,
resetOnCancel = props.resetOnCancel,
restoreDefaultValuesIfChanged = props.restoreDefaultValuesIfChanged,
submitButton = props.submitButton,
/** UserDefined Handlers */
userDefinedOnCancelHandler = props.onCancel,
userDefinedOnInvalidSubmitHandler = props.onInvalidSubmit,
userDefinedOnSubmitHandler = props.onSubmit,
userDefinedOnSubmitErrorHandler = props.onSubmitError,
userDefinedOnSubmitSuccessHandler = props.onSubmitSuccess,
/** Forwarded props to form component */
restFormComponent = __rest(props, [
'autoFocusFirstError',
'breakOnFirstError',
'context',
'defaultValues',
'resolver',
'reValidateOn',
'validateOn',
'actionsWrapper',
'cancelButton',
'children',
'className',
'contentWrapper',
'disabled',
'resetOnCancel',
'restoreDefaultValuesIfChanged',
'submitButton',
'onCancel',
'onInvalidSubmit',
'onSubmit',
'onSubmitError',
'onSubmitSuccess',
]);
// ----
// Initialize HookedForm
// ----
var hookFormCtx = useForm({
mode: validateOn,
reValidateMode: reValidateOn,
defaultValues: defaultValues,
context: context,
shouldFocusError: autoFocusFirstError,
criteriaMode: breakOnFirstError ? 'firstError' : 'all',
resolver: resolver,
});
// ----
// Build Classes
// ----
var state = hookFormCtx.formState,
getValues = hookFormCtx.getValues,
setValue = hookFormCtx.setValue;
var classes = clsx(
{
disabled: disabled,
dirty: state.isDirty,
submitted: state.isSubmitted,
submitting: state.isSubmitting,
valid: state.isValid && !!state.submitCount,
invalid: !state.isValid && !!state.submitCount,
},
'hooked-form',
className
);
// ----
// Default Values Restore
// ----
var resetForm = hookFormCtx.reset;
React.useEffect(
function () {
/** Check if must reset form state */
if (restoreDefaultValuesIfChanged) {
resetForm(defaultValues);
}
},
[resetForm, defaultValues, restoreDefaultValuesIfChanged]
);
// ----
// Handler & Submit Wrapper
// ----
var handleValidFormSubmit = React.useCallback(
function (values) {
return __awaiter(void 0, void 0, void 0, function () {
var result, _a, error_1;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
_b.trys.push([0, 6, , 7]);
if (!(typeof userDefinedOnSubmitHandler === 'function'))
return [3 /*break*/, 2];
return [
4 /*yield*/,
userDefinedOnSubmitHandler(values, hookFormCtx, context || {}),
];
case 1:
_a = _b.sent();
return [3 /*break*/, 3];
case 2:
_a = undefined;
_b.label = 3;
case 3:
result = _a;
if (!(typeof userDefinedOnSubmitSuccessHandler === 'function'))
return [3 /*break*/, 5];
return [
4 /*yield*/,
userDefinedOnSubmitSuccessHandler(
result,
hookFormCtx,
context || {}
),
];
case 4:
return [2 /*return*/, _b.sent()];
case 5:
return [3 /*break*/, 7];
case 6:
error_1 = _b.sent();
/** Call error handler */
if (typeof userDefinedOnSubmitErrorHandler === 'function') {
return [
2 /*return*/,
userDefinedOnSubmitErrorHandler(
error_1,
hookFormCtx,
context || {}
),
];
}
return [3 /*break*/, 7];
case 7:
return [2 /*return*/];
}
});
});
},
[
context,
hookFormCtx,
userDefinedOnSubmitErrorHandler,
userDefinedOnSubmitHandler,
userDefinedOnSubmitSuccessHandler,
]
);
var handleInvalidFormSubmit = React.useCallback(
function (errors) {
return __awaiter(void 0, void 0, void 0, function () {
return __generator(this, function (_a) {
if (typeof userDefinedOnInvalidSubmitHandler === 'function') {
userDefinedOnInvalidSubmitHandler(
errors,
hookFormCtx,
context || {}
);
}
return [2 /*return*/];
});
});
},
[context, hookFormCtx, userDefinedOnInvalidSubmitHandler]
);
var wrappedNativeSubmitHandler = React.useCallback(
function () {
return hookFormCtx.handleSubmit(
handleValidFormSubmit,
handleInvalidFormSubmit
);
},
[handleInvalidFormSubmit, handleValidFormSubmit, hookFormCtx]
);
var handleFormCancel = React.useCallback(
function () {
/** Check if form must be reset */
if (resetOnCancel) {
hookFormCtx.reset();
}
/** Call user defined onCancel handler */
if (typeof userDefinedOnCancelHandler === 'function') {
userDefinedOnCancelHandler(
hookFormCtx.getValues(),
hookFormCtx,
context || {}
);
}
},
[context, hookFormCtx, resetOnCancel, userDefinedOnCancelHandler]
);
// ----
// Field Changed Handlers
// ----
var changeHandlers = React.useRef({});
var registerChangeHandler = React.useCallback(function (field, handler) {
/** Get current ref value */
var currentHandlers = changeHandlers.current;
/** Create the handler array container if doesn't exists */
if (!Array.isArray(currentHandlers[field])) {
currentHandlers[field] = [];
}
/** Add the new handler to handlers container */
currentHandlers[field].push(handler);
/** Return a function to unregister field handler */
return function () {
/** Assert current is not changed */
if (Array.isArray(currentHandlers[field])) {
/** Remove the handler */
currentHandlers[field] = currentHandlers[field].filter(function (
changeHandler
) {
return changeHandler !== handler;
});
}
};
}, []);
var triggerFieldChanged = React.useCallback(function (field, value) {
/** Get current handlers */
var currentHandlers = changeHandlers.current;
/** Check if there are some registered handlers for field change */
if (currentHandlers[field] && Array.isArray(currentHandlers[field])) {
/** Fire all change event handlers */
currentHandlers[field].forEach(function (handler) {
return handler(value);
});
}
}, []);
// ----
// Field Values Watched
// ----
var _a = __read(React.useState({}), 2),
fieldValues = _a[0],
setFieldValues = _a[1];
var useFieldValue = React.useCallback(
function (field) {
/** Register a new handler */
registerChangeHandler(field, function (newValue) {
var _a;
setFieldValues(
__assign(
__assign({}, fieldValues),
((_a = {}), (_a[field] = newValue), _a)
)
);
});
/** Create a nested function to set the new value */
var setNewFieldValue = function (newValue, options) {
setValue(field, newValue, options);
};
/** Return data */
return [
field in fieldValues ? fieldValues[field] : getValues(field),
setNewFieldValue,
];
},
[registerChangeHandler, fieldValues, getValues, setValue]
);
// ----
// Context Value Builder
// ----
var ctxValue = __assign(__assign({}, hookFormCtx), {
handleSubmit: wrappedNativeSubmitHandler,
actionsWrapper: actionsWrapper,
cancelButton: cancelButton,
contentWrapper: contentWrapper,
defaultValues: defaultValues,
disabled: !!disabled,
handleCancel: handleFormCancel,
registerChangeHandler: registerChangeHandler,
submitButton: submitButton,
triggerFieldChanged: triggerFieldChanged,
useFieldValue: useFieldValue,
});
// ----
// Render Component
// ----
return React.createElement(
HookedFormProvider,
{ value: ctxValue },
React.createElement(
Form,
__assign({}, restFormComponent, {
ref: ref,
className: classes,
onSubmit: wrappedNativeSubmitHandler(),
}),
React.createElement(HookedFormContent, null, children),
React.createElement(HookedFormActions, null)
)
);
});
HookedForm.displayName = 'HookedForm';
HookedForm.defaultProps = {
actionsWrapper: 'div',
breakOnFirstError: false,
contentWrapper: 'div',
reValidateOn: 'onChange',
validateOn: 'onSubmit',
};
export { HookedForm as default };