Project Init

This commit is contained in:
Muluhabt
2026-05-29 15:23:46 +03:00
commit 2fbc557aac
67387 changed files with 6063341 additions and 0 deletions

View File

@@ -0,0 +1,16 @@
'use client';
function filterErrors(errors) {
if (errors === null || typeof errors !== "object") {
return {};
}
return Object.keys(errors).reduce((acc, key) => {
const errorValue = errors[key];
if (errorValue !== void 0 && errorValue !== null && errorValue !== false) {
acc[key] = errorValue;
}
return acc;
}, {});
}
export { filterErrors };
//# sourceMappingURL=filter-errors.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"filter-errors.mjs","sources":["../../../../src/hooks/use-form-errors/filter-errors/filter-errors.ts"],"sourcesContent":["import type { FormErrors } from '../../../types';\n\nexport function filterErrors(errors: FormErrors): FormErrors {\n if (errors === null || typeof errors !== 'object') {\n return {};\n }\n\n return Object.keys(errors).reduce<FormErrors>((acc, key) => {\n const errorValue = errors[key];\n\n if (errorValue !== undefined && errorValue !== null && errorValue !== false) {\n acc[key] = errorValue;\n }\n\n return acc;\n }, {});\n}\n"],"names":[],"mappings":";AAEO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAa,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAgC,CAAA;AAC3D,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,MAAA,CAAA,CAAA,CAAA,CAAA,CAAW,CAAA,CAAA,CAAA,CAAA,IAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAA;AACjD,CAAA,CAAA,CAAA,CAAA,OAAO,CAAA,CAAC,CAAA;AAAA,CAAA,CACV,CAAA;AAEA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,EAAO,CAAA,CAAA,CAAA,CAAA,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,EAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAmB,CAAC,CAAA,CAAA,GAAK,GAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAA;AAC1D,CAAA,CAAA,CAAA,CAAA,MAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAa,CAAA,CAAA,CAAA,CAAA,CAAA,EAAO,GAAG,CAAA,CAAA;AAE7B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAe,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAa,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAe,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,MAAe,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAA;AAC3E,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAA,CAAA,CAAG,CAAA,GAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CACb,CAAA;AAEA,CAAA,CAAA,CAAA,CAAA,OAAO,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CACT,CAAA,CAAA,CAAG,CAAA,CAAE,CAAA,CAAA;AACP,CAAA;;"}

View File

@@ -0,0 +1,49 @@
'use client';
import { useState, useRef, useCallback } from 'react';
import { filterErrors } from './filter-errors/filter-errors.mjs';
function useFormErrors(initialErrors) {
const [errorsState, setErrorsState] = useState(filterErrors(initialErrors));
const errorsRef = useRef(errorsState);
const setErrors = useCallback((errors) => {
setErrorsState((current) => {
const newErrors = filterErrors(typeof errors === "function" ? errors(current) : errors);
errorsRef.current = newErrors;
return newErrors;
});
}, []);
const clearErrors = useCallback(() => setErrors({}), []);
const clearFieldError = useCallback(
(path) => {
if (errorsRef.current[path] === void 0) {
return;
}
setErrors((current) => {
const errors = { ...current };
delete errors[path];
return errors;
});
},
[errorsState]
);
const setFieldError = useCallback(
(path, error) => {
if (error == null || error === false) {
clearFieldError(path);
} else if (errorsRef.current[path] !== error) {
setErrors((current) => ({ ...current, [path]: error }));
}
},
[errorsState]
);
return {
errorsState,
setErrors,
clearErrors,
setFieldError,
clearFieldError
};
}
export { useFormErrors };
//# sourceMappingURL=use-form-errors.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,51 @@
'use client';
import { useCallback } from 'react';
import { changeErrorIndices } from '../../lists/change-error-indices.mjs';
import { reorderErrors } from '../../lists/reorder-errors.mjs';
import 'klona/full';
import { reorderPath } from '../../paths/reorder-path.mjs';
import { insertPath } from '../../paths/insert-path.mjs';
import { removePath } from '../../paths/remove-path.mjs';
import { replacePath } from '../../paths/replace-path.mjs';
function useFormList({
$values,
$errors,
$status
}) {
const reorderListItem = useCallback((path, payload) => {
$status.clearFieldDirty(path);
$errors.setErrors((errs) => reorderErrors(path, payload, errs));
$values.setValues({
values: reorderPath(path, payload, $values.refValues.current),
updateState: true
});
}, []);
const removeListItem = useCallback((path, index) => {
$status.clearFieldDirty(path);
$errors.setErrors((errs) => changeErrorIndices(path, index, errs, -1));
$values.setValues({
values: removePath(path, index, $values.refValues.current),
updateState: true
});
}, []);
const insertListItem = useCallback((path, item, index) => {
$status.clearFieldDirty(path);
$errors.setErrors((errs) => changeErrorIndices(path, index, errs, 1));
$values.setValues({
values: insertPath(path, item, index, $values.refValues.current),
updateState: true
});
}, []);
const replaceListItem = useCallback((path, index, item) => {
$status.clearFieldDirty(path);
$values.setValues({
values: replacePath(path, item, index, $values.refValues.current),
updateState: true
});
}, []);
return { reorderListItem, removeListItem, insertListItem, replaceListItem };
}
export { useFormList };
//# sourceMappingURL=use-form-list.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,124 @@
'use client';
import { useState, useRef, useCallback } from 'react';
import isEqual from 'fast-deep-equal';
import { getStatus } from '../../get-status/get-status.mjs';
import { clearListState } from '../../lists/clear-list-state.mjs';
import { getPath } from '../../paths/get-path.mjs';
import 'klona/full';
function useFormStatus({
initialDirty,
initialTouched,
mode,
$values
}) {
const [touchedState, setTouchedState] = useState(initialTouched);
const [dirtyState, setDirtyState] = useState(initialDirty);
const touchedRef = useRef(initialTouched);
const dirtyRef = useRef(initialDirty);
const setTouched = useCallback((values) => {
const resolvedValues = typeof values === "function" ? values(touchedRef.current) : values;
touchedRef.current = resolvedValues;
if (mode === "controlled") {
setTouchedState(resolvedValues);
}
}, []);
const setDirty = useCallback(
(values, forceUpdate = false) => {
const resolvedValues = typeof values === "function" ? values(dirtyRef.current) : values;
dirtyRef.current = resolvedValues;
if (mode === "controlled" || forceUpdate) {
setDirtyState(resolvedValues);
}
},
[]
);
const resetTouched = useCallback(() => setTouched({}), []);
const resetDirty = useCallback((values) => {
const newSnapshot = values ? { ...$values.refValues.current, ...values } : $values.refValues.current;
$values.setValuesSnapshot(newSnapshot);
setDirty({});
}, []);
const setFieldTouched = useCallback((path, touched) => {
setTouched((currentTouched) => {
if (getStatus(currentTouched, path) === touched) {
return currentTouched;
}
return { ...currentTouched, [path]: touched };
});
}, []);
const setFieldDirty = useCallback((path, dirty, forceUpdate) => {
setDirty((currentDirty) => {
if (getStatus(currentDirty, path) === dirty) {
return currentDirty;
}
return { ...currentDirty, [path]: dirty };
}, forceUpdate);
}, []);
const setCalculatedFieldDirty = useCallback((path, value) => {
const currentDirty = getStatus(dirtyRef.current, path);
const dirty = !isEqual(getPath(path, $values.getValuesSnapshot()), value);
const clearedState = clearListState(path, dirtyRef.current);
clearedState[path] = dirty;
setDirty(clearedState, currentDirty !== dirty);
}, []);
const isTouched = useCallback(
(path) => getStatus(touchedRef.current, path),
[]
);
const clearFieldDirty = useCallback(
(path) => setDirty((current) => {
if (typeof path !== "string") {
return current;
}
const result = clearListState(path, current);
delete result[path];
if (isEqual(result, current)) {
return current;
}
return result;
}),
[]
);
const isDirty = useCallback((path) => {
if (path) {
const overriddenValue = getPath(path, dirtyRef.current);
if (typeof overriddenValue === "boolean") {
return overriddenValue;
}
const sliceOfValues = getPath(path, $values.refValues.current);
const sliceOfInitialValues = getPath(path, $values.valuesSnapshot.current);
return !isEqual(sliceOfValues, sliceOfInitialValues);
}
const isOverridden = Object.keys(dirtyRef.current).length > 0;
if (isOverridden) {
return getStatus(dirtyRef.current);
}
return !isEqual($values.refValues.current, $values.valuesSnapshot.current);
}, []);
const getDirty = useCallback(() => dirtyRef.current, []);
const getTouched = useCallback(() => touchedRef.current, []);
return {
touchedState,
dirtyState,
touchedRef,
dirtyRef,
setTouched,
setDirty,
resetDirty,
resetTouched,
isTouched,
setFieldTouched,
setFieldDirty,
setTouchedState,
setDirtyState,
clearFieldDirty,
isDirty,
getDirty,
getTouched,
setCalculatedFieldDirty
};
}
export { useFormStatus };
//# sourceMappingURL=use-form-status.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,107 @@
'use client';
import { useRef, useState, useCallback } from 'react';
import { getPath } from '../../paths/get-path.mjs';
import { setPath } from '../../paths/set-path.mjs';
function useFormValues({
initialValues,
onValuesChange,
mode
}) {
const initialized = useRef(false);
const [stateValues, setStateValues] = useState(initialValues || {});
const refValues = useRef(stateValues);
const valuesSnapshot = useRef(stateValues);
const setValues = useCallback(
({
values,
subscribers,
updateState = true,
mergeWithPreviousValues = true
}) => {
const previousValues = refValues.current;
const resolvedValues = values instanceof Function ? values(refValues.current) : values;
const updatedValues = mergeWithPreviousValues ? { ...previousValues, ...resolvedValues } : resolvedValues;
refValues.current = updatedValues;
if (updateState) {
setStateValues(updatedValues);
if (mode === "uncontrolled") {
refValues.current = updatedValues;
}
}
onValuesChange?.(updatedValues, previousValues);
subscribers?.filter(Boolean).forEach((subscriber) => subscriber({ updatedValues, previousValues }));
},
[onValuesChange]
);
const setFieldValue = useCallback(
(payload) => {
const currentValue = getPath(payload.path, refValues.current);
const updatedValue = payload.value instanceof Function ? payload.value(currentValue) : payload.value;
if (currentValue !== updatedValue) {
const previousValues = refValues.current;
const updatedValues = setPath(payload.path, updatedValue, refValues.current);
setValues({ values: updatedValues, updateState: payload.updateState });
payload.subscribers?.filter(Boolean).forEach(
(subscriber) => subscriber({ path: payload.path, updatedValues, previousValues })
);
}
},
[setValues]
);
const setValuesSnapshot = useCallback((payload) => {
valuesSnapshot.current = payload;
}, []);
const initialize = useCallback(
(values, onInitialize) => {
if (!initialized.current) {
initialized.current = true;
setValues({ values, updateState: mode === "controlled" });
setValuesSnapshot(values);
onInitialize();
}
},
[setValues]
);
const resetValues = useCallback(() => {
setValues({
values: valuesSnapshot.current,
updateState: true,
mergeWithPreviousValues: false
});
}, [setValues]);
const getValues = useCallback(() => refValues.current, []);
const getValuesSnapshot = useCallback(() => valuesSnapshot.current, []);
const resetField = useCallback(
(path, subscribers) => {
const snapshotValue = getPath(path, valuesSnapshot.current);
if (typeof snapshotValue === "undefined") {
return;
}
setFieldValue({
path,
value: snapshotValue,
updateState: mode === "controlled",
subscribers
});
},
[setFieldValue, mode]
);
return {
initialized,
stateValues,
refValues,
valuesSnapshot,
setValues,
setFieldValue,
resetValues,
setValuesSnapshot,
initialize,
getValues,
getValuesSnapshot,
resetField
};
}
export { useFormValues };
//# sourceMappingURL=use-form-values.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,57 @@
'use client';
import { useRef, useCallback, useEffect } from 'react';
import { getPath } from '../../paths/get-path.mjs';
import 'klona/full';
function useFormWatch({
$status,
cascadeUpdates
}) {
const subscribers = useRef(
{}
);
const watch = useCallback((path, callback) => {
useEffect(() => {
subscribers.current[path] = subscribers.current[path] || [];
subscribers.current[path].push(callback);
return () => {
subscribers.current[path] = subscribers.current[path].filter((cb) => cb !== callback);
};
}, [callback]);
}, []);
const getFieldSubscribers = useCallback((path) => {
const result = subscribers.current[path]?.map(
(callback) => (input) => callback({
previousValue: getPath(path, input.previousValues),
value: getPath(path, input.updatedValues),
touched: $status.isTouched(path),
dirty: $status.isDirty(path)
})
) ?? [];
if (cascadeUpdates) {
for (const subscriptionKey in subscribers.current) {
if (subscriptionKey.startsWith(`${path}.`) || path.startsWith(`${subscriptionKey}.`)) {
result.push(
...subscribers.current[subscriptionKey].map(
(cb) => (input) => cb({
previousValue: getPath(subscriptionKey, input.previousValues),
value: getPath(subscriptionKey, input.updatedValues),
touched: $status.isTouched(subscriptionKey),
dirty: $status.isDirty(subscriptionKey)
})
)
);
}
}
}
return result;
}, []);
return {
subscribers,
watch,
getFieldSubscribers
};
}
export { useFormWatch };
//# sourceMappingURL=use-form-watch.mjs.map

File diff suppressed because one or more lines are too long