@felte/core
Advanced tools
Comparing version 1.0.0-next.13 to 1.0.0-next.14
@@ -334,5 +334,5 @@ 'use strict'; | ||
return; | ||
if (objValue === null) | ||
if (objValue === null || objValue === '') | ||
return srcValue; | ||
if (srcValue === null) | ||
if (srcValue === null || srcValue === '') | ||
return objValue; | ||
@@ -347,9 +347,16 @@ if (!objValue || !srcValue) | ||
} | ||
function mergeErrors(errors) { | ||
return _mergeWith(...errors, executeCustomizer); | ||
} | ||
function runValidations(values, validationOrValidations) { | ||
if (!validationOrValidations) | ||
return []; | ||
const validations = Array.isArray(validationOrValidations) | ||
? validationOrValidations | ||
: [validationOrValidations]; | ||
return validations.map((v) => v(values)); | ||
} | ||
async function executeValidation(values, validations) { | ||
if (!validations) | ||
return; | ||
if (!Array.isArray(validations)) | ||
return validations(values); | ||
const errorArray = await Promise.all(validations.map((v) => v(values))); | ||
return _mergeWith(...errorArray, executeCustomizer); | ||
const errors = await Promise.all(runValidations(values, validations)); | ||
return mergeErrors(errors); | ||
} | ||
@@ -526,2 +533,11 @@ | ||
function getAllValidators(prop, config) { | ||
var _a, _b, _c; | ||
const validate = (_a = config[prop]) !== null && _a !== void 0 ? _a : []; | ||
const validations = Array.isArray(validate) ? validate : [validate]; | ||
const debounced = (_c = (_b = config.debounced) === null || _b === void 0 ? void 0 : _b[prop]) !== null && _c !== void 0 ? _c : []; | ||
const debValidations = Array.isArray(debounced) ? debounced : [debounced]; | ||
return [...validations, ...debValidations]; | ||
} | ||
function addAtIndex(storeValue, path, value, index) { | ||
@@ -583,2 +599,11 @@ return _update(storeValue, path, (oldValue) => { | ||
function unsetField(path) { | ||
data.update(($data) => { | ||
const newData = _unset($data, path); | ||
if (formNode) | ||
setForm(formNode, newData); | ||
return newData; | ||
}); | ||
touched.update(($touched) => { | ||
return _unset($touched, path); | ||
}); | ||
errors.update(($errors) => { | ||
@@ -590,11 +615,2 @@ return _unset($errors, path); | ||
}); | ||
touched.update(($touched) => { | ||
return _unset($touched, path); | ||
}); | ||
data.update(($data) => { | ||
const newData = _unset($data, path); | ||
if (formNode) | ||
setForm(formNode, newData); | ||
return newData; | ||
}); | ||
} | ||
@@ -638,10 +654,14 @@ function addField(path, value, index) { | ||
async function validate() { | ||
const validate = getAllValidators('validate', config); | ||
const warn = getAllValidators('warn', config); | ||
const currentData = get(data); | ||
const initialErrors = deepSet(currentData, null); | ||
setTouched((t) => { | ||
return deepSet(t, true); | ||
}); | ||
const currentErrors = await executeValidation(currentData, config.validate); | ||
const currentWarnings = await executeValidation(currentData, config.warn); | ||
warnings.set(_merge(deepSet(currentData, null), currentWarnings || {})); | ||
errors.set(currentErrors || {}); | ||
const partialErrors = await executeValidation(currentData, validate); | ||
const currentErrors = _merge(initialErrors, partialErrors); | ||
const currentWarnings = await executeValidation(currentData, warn); | ||
warnings.set(_merge(initialErrors, currentWarnings || {})); | ||
errors.set(currentErrors || initialErrors); | ||
return currentErrors; | ||
@@ -656,28 +676,30 @@ } | ||
} | ||
return { | ||
public: { | ||
setData, | ||
setFields, | ||
setTouched, | ||
setErrors, | ||
setWarnings, | ||
setIsSubmitting, | ||
setIsDirty, | ||
validate, | ||
reset, | ||
unsetField, | ||
resetField, | ||
addField, | ||
setInitialValues: (values) => { | ||
initialValues = values; | ||
}, | ||
const publicHelpers = { | ||
setData, | ||
setFields, | ||
setTouched, | ||
setErrors, | ||
setWarnings, | ||
setIsSubmitting, | ||
setIsDirty, | ||
validate, | ||
reset, | ||
unsetField, | ||
resetField, | ||
addField, | ||
setInitialValues: (values) => { | ||
initialValues = values; | ||
}, | ||
private: { | ||
_setFormNode: (node) => { | ||
formNode = node; | ||
}, | ||
_getFormNode: () => formNode, | ||
_getInitialValues: () => initialValues, | ||
}; | ||
const privateHelpers = { | ||
_setFormNode: (node) => { | ||
formNode = node; | ||
}, | ||
_getFormNode: () => formNode, | ||
_getInitialValues: () => initialValues, | ||
}; | ||
return { | ||
public: publicHelpers, | ||
private: privateHelpers, | ||
}; | ||
} | ||
@@ -752,8 +774,8 @@ | ||
const { setFields, setTouched, reset, setInitialValues } = helpers; | ||
const { addValidator, addWarnValidator, addTransformer, validate, setIsDirty, setIsSubmitting } = helpers, contextHelpers = __rest(helpers, ["addValidator", "addWarnValidator", "addTransformer", "validate", "setIsDirty", "setIsSubmitting"]); | ||
const { addValidator, addTransformer, validate, setIsDirty, setIsSubmitting } = helpers, contextHelpers = __rest(helpers, ["addValidator", "addTransformer", "validate", "setIsDirty", "setIsSubmitting"]); | ||
const { data, errors, warnings, touched, isSubmitting, isDirty } = stores; | ||
function createSubmitHandler(altConfig) { | ||
var _a, _b, _c, _d; | ||
const validate = (_a = altConfig === null || altConfig === void 0 ? void 0 : altConfig.validate) !== null && _a !== void 0 ? _a : config.validate; | ||
const warn = (_b = altConfig === null || altConfig === void 0 ? void 0 : altConfig.warn) !== null && _b !== void 0 ? _b : config.warn; | ||
const validate = (_a = altConfig === null || altConfig === void 0 ? void 0 : altConfig.validate) !== null && _a !== void 0 ? _a : getAllValidators('validate', config); | ||
const warn = (_b = altConfig === null || altConfig === void 0 ? void 0 : altConfig.warn) !== null && _b !== void 0 ? _b : getAllValidators('warn', config); | ||
const onError = (_c = altConfig === null || altConfig === void 0 ? void 0 : altConfig.onError) !== null && _c !== void 0 ? _c : config.onError; | ||
@@ -770,3 +792,4 @@ const onSuccess = (_d = altConfig === null || altConfig === void 0 ? void 0 : altConfig.onSuccess) !== null && _d !== void 0 ? _d : config.onSuccess; | ||
const currentData = get(data); | ||
const currentErrors = await executeValidation(currentData, validate); | ||
const partialErrors = await executeValidation(currentData, validate); | ||
const currentErrors = _merge(deepSet(currentData, null), partialErrors); | ||
const currentWarnings = await executeValidation(currentData, warn); | ||
@@ -840,3 +863,2 @@ if (currentWarnings) | ||
addValidator, | ||
addWarnValidator, | ||
addTransformer, | ||
@@ -955,2 +977,8 @@ setFields, | ||
continue; | ||
data.update(($data) => { | ||
return _unset($data, getPathFromDataset(control)); | ||
}); | ||
touched.update(($touched) => { | ||
return _unset($touched, getPathFromDataset(control)); | ||
}); | ||
errors.update(($errors) => { | ||
@@ -962,8 +990,2 @@ return _unset($errors, getPathFromDataset(control)); | ||
}); | ||
touched.update(($touched) => { | ||
return _unset($touched, getPathFromDataset(control)); | ||
}); | ||
data.update(($data) => { | ||
return _unset($data, getPathFromDataset(control)); | ||
}); | ||
} | ||
@@ -1056,2 +1078,11 @@ } | ||
function createAbortController() { | ||
const signal = { aborted: false }; | ||
return { | ||
signal, | ||
abort() { | ||
signal.aborted = true; | ||
}, | ||
}; | ||
} | ||
function errorFilterer(errValue, touchValue) { | ||
@@ -1068,3 +1099,67 @@ if (_isPlainObject(touchValue)) | ||
} | ||
function filterErrors([errors, touched]) { | ||
return _mergeWith(errors, touched, errorFilterer); | ||
} | ||
function debounce(func, timeout = 300) { | ||
let timer; | ||
return (...args) => { | ||
clearTimeout(timer); | ||
timer = setTimeout(() => { | ||
func.apply(this, args); | ||
}, timeout); | ||
}; | ||
} | ||
function cancellableValidation(store) { | ||
let activeController; | ||
return async function executeValidations($data, validations) { | ||
if (!validations || !$data) | ||
return; | ||
let current = deepSet($data, null); | ||
const controller = createAbortController(); | ||
if (activeController) | ||
activeController.abort(); | ||
activeController = controller; | ||
const results = runValidations($data, validations); | ||
results.forEach(async (promise) => { | ||
const result = await promise; | ||
if (controller.signal.aborted) | ||
return; | ||
current = mergeErrors([current, result]); | ||
store.set(current); | ||
}); | ||
}; | ||
} | ||
function createDerivedFactory(storeFactory) { | ||
return function derived(storeOrStores, deriver, initialValue) { | ||
const stores = Array.isArray(storeOrStores) | ||
? storeOrStores | ||
: [storeOrStores]; | ||
const values = new Array(stores.length); | ||
const derivedStore = storeFactory(initialValue); | ||
const storeSet = derivedStore.set; | ||
const storeSubscribe = derivedStore.subscribe; | ||
let unsubscribers; | ||
function startStore() { | ||
unsubscribers = stores.map((store, index) => { | ||
return store.subscribe(($store) => { | ||
values[index] = $store; | ||
storeSet(deriver(values)); | ||
}); | ||
}); | ||
} | ||
function stopStore() { | ||
unsubscribers === null || unsubscribers === void 0 ? void 0 : unsubscribers.forEach((unsub) => unsub()); | ||
} | ||
derivedStore.subscribe = function subscribe(subscriber) { | ||
const unsubscribe = storeSubscribe(subscriber); | ||
return () => { | ||
unsubscribe(); | ||
}; | ||
}; | ||
return [derivedStore, startStore, stopStore]; | ||
}; | ||
} | ||
function createStores(storeFactory, config) { | ||
var _a, _b, _c, _d, _e, _f, _g; | ||
const derived = createDerivedFactory(storeFactory); | ||
const initialValues = config.initialValues | ||
@@ -1075,65 +1170,69 @@ ? executeTransforms(_cloneDeep(config.initialValues), config.transform) | ||
const initialErrors = deepSet(initialValues, null); | ||
const errors = storeFactory(initialErrors); | ||
const filteredErrors = storeFactory(_cloneDeep(initialErrors)); | ||
const filteredErrorsSet = filteredErrors.set; | ||
const immediateErrors = storeFactory(initialErrors); | ||
const debouncedErrors = storeFactory(_cloneDeep(initialErrors)); | ||
const [errors, startErrors, stopErrors] = derived([ | ||
immediateErrors, | ||
debouncedErrors, | ||
], mergeErrors, _cloneDeep(initialErrors)); | ||
const initialWarnings = deepSet(initialValues, null); | ||
const warnings = storeFactory(initialWarnings); | ||
const immediateWarnings = storeFactory(initialWarnings); | ||
const debouncedWarnings = storeFactory(_cloneDeep(initialWarnings)); | ||
const [warnings, startWarnings, stopWarnings] = derived([ | ||
immediateWarnings, | ||
debouncedWarnings, | ||
], mergeErrors, _cloneDeep(initialWarnings)); | ||
const initialTouched = deepSet(initialValues, false); | ||
const touched = storeFactory(initialTouched); | ||
const isValid = storeFactory(!config.validate); | ||
const [filteredErrors, startFilteredErrors, stopFilteredErrors] = derived([errors, touched], filterErrors, _cloneDeep(initialErrors)); | ||
let firstCalled = false; | ||
const [isValid, startIsValid, stopIsValid] = derived(errors, ([$errors]) => { | ||
var _a; | ||
if (!firstCalled) { | ||
firstCalled = true; | ||
return !config.validate && !((_a = config.debounced) === null || _a === void 0 ? void 0 : _a.validate); | ||
} | ||
else { | ||
return !deepSome($errors, (error) => !!error); | ||
} | ||
}, !config.validate && !((_a = config.debounced) === null || _a === void 0 ? void 0 : _a.validate)); | ||
delete isValid.set; | ||
delete isValid.update; | ||
const isSubmitting = storeFactory(false); | ||
const isDirty = storeFactory(false); | ||
async function validateErrors($data) { | ||
let currentErrors = {}; | ||
if (!config.validate || !$data) | ||
return; | ||
currentErrors = await executeValidation($data, config.validate); | ||
errors.set(currentErrors || {}); | ||
} | ||
async function validateWarnings($data) { | ||
let currentWarnings = {}; | ||
if (!config.warn || !$data) | ||
return; | ||
currentWarnings = await executeValidation($data, config.warn); | ||
warnings.set(_merge(deepSet($data, null), currentWarnings || {})); | ||
} | ||
const validateErrors = cancellableValidation(immediateErrors); | ||
const validateWarnings = cancellableValidation(immediateWarnings); | ||
const validateDebouncedErrors = debounce(cancellableValidation(debouncedErrors), (_c = (_b = config.debounced) === null || _b === void 0 ? void 0 : _b.validateTimeout) !== null && _c !== void 0 ? _c : (_d = config.debounced) === null || _d === void 0 ? void 0 : _d.timeout); | ||
const validateDebouncedWarnings = debounce(cancellableValidation(debouncedWarnings), (_f = (_e = config.debounced) === null || _e === void 0 ? void 0 : _e.warnTimeout) !== null && _f !== void 0 ? _f : (_g = config.debounced) === null || _g === void 0 ? void 0 : _g.timeout); | ||
function start() { | ||
const dataUnsubscriber = data.subscribe(($data) => { | ||
validateErrors($data); | ||
validateWarnings($data); | ||
var _a, _b; | ||
validateErrors($data, config.validate); | ||
validateWarnings($data, config.warn); | ||
debouncedErrors.set({}); | ||
validateDebouncedErrors($data, (_a = config.debounced) === null || _a === void 0 ? void 0 : _a.validate); | ||
debouncedWarnings.set({}); | ||
validateDebouncedWarnings($data, (_b = config.debounced) === null || _b === void 0 ? void 0 : _b.warn); | ||
}); | ||
let touchedValue = initialTouched; | ||
let errorsValue = initialErrors; | ||
let firstCalled = false; | ||
const errorsUnsubscriber = errors.subscribe(($errors) => { | ||
if (!firstCalled) { | ||
firstCalled = true; | ||
isValid.set(!config.validate); | ||
} | ||
else { | ||
const hasErrors = deepSome($errors, (error) => !!error); | ||
isValid.set(!hasErrors); | ||
} | ||
errorsValue = $errors; | ||
const mergedErrors = _mergeWith($errors, touchedValue, errorFilterer); | ||
filteredErrorsSet(mergedErrors); | ||
}); | ||
const touchedUnsubscriber = touched.subscribe(($touched) => { | ||
touchedValue = $touched; | ||
const mergedErrors = _mergeWith(errorsValue, $touched, errorFilterer); | ||
filteredErrorsSet(mergedErrors); | ||
}); | ||
startErrors(); | ||
startIsValid(); | ||
startWarnings(); | ||
startFilteredErrors(); | ||
function cleanup() { | ||
dataUnsubscriber(); | ||
errorsUnsubscriber(); | ||
touchedUnsubscriber(); | ||
stopFilteredErrors(); | ||
stopErrors(); | ||
stopWarnings(); | ||
stopIsValid(); | ||
} | ||
return cleanup; | ||
} | ||
filteredErrors.set = errors.set; | ||
filteredErrors.update = errors.update; | ||
filteredErrors.set = immediateErrors.set; | ||
filteredErrors.update = | ||
immediateErrors.update; | ||
warnings.set = immediateWarnings.set; | ||
warnings.update = immediateWarnings.update; | ||
return { | ||
data, | ||
errors: filteredErrors, | ||
warnings, | ||
warnings: warnings, | ||
touched, | ||
@@ -1149,7 +1248,10 @@ isValid, | ||
function createForm(config, adapters) { | ||
var _a, _b; | ||
var _a, _b, _c; | ||
(_a = config.extend) !== null && _a !== void 0 ? _a : (config.extend = []); | ||
(_b = config.touchTriggerEvents) !== null && _b !== void 0 ? _b : (config.touchTriggerEvents = { change: true, blur: true }); | ||
(_b = config.debounced) !== null && _b !== void 0 ? _b : (config.debounced = {}); | ||
(_c = config.touchTriggerEvents) !== null && _c !== void 0 ? _c : (config.touchTriggerEvents = { change: true, blur: true }); | ||
if (config.validate && !Array.isArray(config.validate)) | ||
config.validate = [config.validate]; | ||
if (config.debounced.validate && !Array.isArray(config.debounced.validate)) | ||
config.debounced.validate = [config.debounced.validate]; | ||
if (config.transform && !Array.isArray(config.transform)) | ||
@@ -1159,9 +1261,18 @@ config.transform = [config.transform]; | ||
config.warn = [config.warn]; | ||
function addValidator(validator) { | ||
if (!config.validate) { | ||
config.validate = [validator]; | ||
if (config.debounced.warn && !Array.isArray(config.debounced.warn)) | ||
config.debounced.warn = [config.debounced.warn]; | ||
function addValidator(validator, { debounced, level } = { | ||
debounced: false, | ||
level: 'error', | ||
}) { | ||
var _a; | ||
const prop = level === 'error' ? 'validate' : 'warn'; | ||
(_a = config.debounced) !== null && _a !== void 0 ? _a : (config.debounced = {}); | ||
const validateConfig = debounced ? config.debounced : config; | ||
if (!validateConfig[prop]) { | ||
validateConfig[prop] = [validator]; | ||
} | ||
else { | ||
config.validate = [ | ||
...config.validate, | ||
validateConfig[prop] = [ | ||
...validateConfig[prop], | ||
validator, | ||
@@ -1171,10 +1282,2 @@ ]; | ||
} | ||
function addWarnValidator(validator) { | ||
if (!config.warn) { | ||
config.warn = [validator]; | ||
} | ||
else { | ||
config.warn = [...config.warn, validator]; | ||
} | ||
} | ||
function addTransformer(transformer) { | ||
@@ -1225,3 +1328,2 @@ if (!config.transform) { | ||
addValidator, | ||
addWarnValidator, | ||
addTransformer, | ||
@@ -1254,3 +1356,3 @@ setFields: helpers.public.setFields, | ||
} | ||
const { form, createSubmitHandler, handleSubmit } = createFormAction(Object.assign({ config, stores: { | ||
const formActionConfig = Object.assign({ config, stores: { | ||
data: clonedData, | ||
@@ -1264,6 +1366,6 @@ touched, | ||
}, helpers: Object.assign(Object.assign({}, helpers.public), { addTransformer, | ||
addValidator, | ||
addWarnValidator }), extender, | ||
addValidator }), extender, | ||
_getCurrentExtenders, | ||
_setCurrentExtenders }, helpers.private)); | ||
_setCurrentExtenders }, helpers.private); | ||
const { form, createSubmitHandler, handleSubmit } = createFormAction(formActionConfig); | ||
data.set = newDataSet; | ||
@@ -1316,2 +1418,4 @@ return Object.assign({ data, | ||
exports.isTextAreaElement = isTextAreaElement; | ||
exports.mergeErrors = mergeErrors; | ||
exports.runValidations = runValidations; | ||
exports.setControlValue = setControlValue; | ||
@@ -1318,0 +1422,0 @@ exports.setForm = setForm; |
import { __rest } from './external/.pnpm/tslib@2.3.1/external/tslib/tslib.es6.js'; | ||
import { get } from './get.js'; | ||
import { FelteSubmitError } from './error.js'; | ||
import { getAllValidators } from './get-validators.js'; | ||
import { executeValidation } from './packages/common/dist/esm/utils/executeValidation.js'; | ||
@@ -60,8 +61,8 @@ import { _merge } from './packages/common/dist/esm/utils/merge.js'; | ||
const { setFields, setTouched, reset, setInitialValues } = helpers; | ||
const { addValidator, addWarnValidator, addTransformer, validate, setIsDirty, setIsSubmitting } = helpers, contextHelpers = __rest(helpers, ["addValidator", "addWarnValidator", "addTransformer", "validate", "setIsDirty", "setIsSubmitting"]); | ||
const { addValidator, addTransformer, validate, setIsDirty, setIsSubmitting } = helpers, contextHelpers = __rest(helpers, ["addValidator", "addTransformer", "validate", "setIsDirty", "setIsSubmitting"]); | ||
const { data, errors, warnings, touched, isSubmitting, isDirty } = stores; | ||
function createSubmitHandler(altConfig) { | ||
var _a, _b, _c, _d; | ||
const validate = (_a = altConfig === null || altConfig === void 0 ? void 0 : altConfig.validate) !== null && _a !== void 0 ? _a : config.validate; | ||
const warn = (_b = altConfig === null || altConfig === void 0 ? void 0 : altConfig.warn) !== null && _b !== void 0 ? _b : config.warn; | ||
const validate = (_a = altConfig === null || altConfig === void 0 ? void 0 : altConfig.validate) !== null && _a !== void 0 ? _a : getAllValidators('validate', config); | ||
const warn = (_b = altConfig === null || altConfig === void 0 ? void 0 : altConfig.warn) !== null && _b !== void 0 ? _b : getAllValidators('warn', config); | ||
const onError = (_c = altConfig === null || altConfig === void 0 ? void 0 : altConfig.onError) !== null && _c !== void 0 ? _c : config.onError; | ||
@@ -78,3 +79,4 @@ const onSuccess = (_d = altConfig === null || altConfig === void 0 ? void 0 : altConfig.onSuccess) !== null && _d !== void 0 ? _d : config.onSuccess; | ||
const currentData = get(data); | ||
const currentErrors = await executeValidation(currentData, validate); | ||
const partialErrors = await executeValidation(currentData, validate); | ||
const currentErrors = _merge(deepSet(currentData, null), partialErrors); | ||
const currentWarnings = await executeValidation(currentData, warn); | ||
@@ -148,3 +150,2 @@ if (currentWarnings) | ||
addValidator, | ||
addWarnValidator, | ||
addTransformer, | ||
@@ -263,2 +264,8 @@ setFields, | ||
continue; | ||
data.update(($data) => { | ||
return _unset($data, getPathFromDataset(control)); | ||
}); | ||
touched.update(($touched) => { | ||
return _unset($touched, getPathFromDataset(control)); | ||
}); | ||
errors.update(($errors) => { | ||
@@ -270,8 +277,2 @@ return _unset($errors, getPathFromDataset(control)); | ||
}); | ||
touched.update(($touched) => { | ||
return _unset($touched, getPathFromDataset(control)); | ||
}); | ||
data.update(($data) => { | ||
return _unset($data, getPathFromDataset(control)); | ||
}); | ||
} | ||
@@ -278,0 +279,0 @@ } |
@@ -10,7 +10,10 @@ import { createHelpers } from './helpers.js'; | ||
function createForm(config, adapters) { | ||
var _a, _b; | ||
var _a, _b, _c; | ||
(_a = config.extend) !== null && _a !== void 0 ? _a : (config.extend = []); | ||
(_b = config.touchTriggerEvents) !== null && _b !== void 0 ? _b : (config.touchTriggerEvents = { change: true, blur: true }); | ||
(_b = config.debounced) !== null && _b !== void 0 ? _b : (config.debounced = {}); | ||
(_c = config.touchTriggerEvents) !== null && _c !== void 0 ? _c : (config.touchTriggerEvents = { change: true, blur: true }); | ||
if (config.validate && !Array.isArray(config.validate)) | ||
config.validate = [config.validate]; | ||
if (config.debounced.validate && !Array.isArray(config.debounced.validate)) | ||
config.debounced.validate = [config.debounced.validate]; | ||
if (config.transform && !Array.isArray(config.transform)) | ||
@@ -20,9 +23,18 @@ config.transform = [config.transform]; | ||
config.warn = [config.warn]; | ||
function addValidator(validator) { | ||
if (!config.validate) { | ||
config.validate = [validator]; | ||
if (config.debounced.warn && !Array.isArray(config.debounced.warn)) | ||
config.debounced.warn = [config.debounced.warn]; | ||
function addValidator(validator, { debounced, level } = { | ||
debounced: false, | ||
level: 'error', | ||
}) { | ||
var _a; | ||
const prop = level === 'error' ? 'validate' : 'warn'; | ||
(_a = config.debounced) !== null && _a !== void 0 ? _a : (config.debounced = {}); | ||
const validateConfig = debounced ? config.debounced : config; | ||
if (!validateConfig[prop]) { | ||
validateConfig[prop] = [validator]; | ||
} | ||
else { | ||
config.validate = [ | ||
...config.validate, | ||
validateConfig[prop] = [ | ||
...validateConfig[prop], | ||
validator, | ||
@@ -32,10 +44,2 @@ ]; | ||
} | ||
function addWarnValidator(validator) { | ||
if (!config.warn) { | ||
config.warn = [validator]; | ||
} | ||
else { | ||
config.warn = [...config.warn, validator]; | ||
} | ||
} | ||
function addTransformer(transformer) { | ||
@@ -86,3 +90,2 @@ if (!config.transform) { | ||
addValidator, | ||
addWarnValidator, | ||
addTransformer, | ||
@@ -115,3 +118,3 @@ setFields: helpers.public.setFields, | ||
} | ||
const { form, createSubmitHandler, handleSubmit } = createFormAction(Object.assign({ config, stores: { | ||
const formActionConfig = Object.assign({ config, stores: { | ||
data: clonedData, | ||
@@ -125,6 +128,6 @@ touched, | ||
}, helpers: Object.assign(Object.assign({}, helpers.public), { addTransformer, | ||
addValidator, | ||
addWarnValidator }), extender, | ||
addValidator }), extender, | ||
_getCurrentExtenders, | ||
_setCurrentExtenders }, helpers.private)); | ||
_setCurrentExtenders }, helpers.private); | ||
const { form, createSubmitHandler, handleSubmit } = createFormAction(formActionConfig); | ||
data.set = newDataSet; | ||
@@ -131,0 +134,0 @@ return Object.assign({ data, |
import { get } from './get.js'; | ||
import { getAllValidators } from './get-validators.js'; | ||
import { _get } from './packages/common/dist/esm/utils/get.js'; | ||
import { _set } from './packages/common/dist/esm/utils/set.js'; | ||
import { _unset } from './packages/common/dist/esm/utils/unset.js'; | ||
import { setForm } from './packages/common/dist/esm/utils/domUtils.js'; | ||
import { _update } from './packages/common/dist/esm/utils/update.js'; | ||
import { _get } from './packages/common/dist/esm/utils/get.js'; | ||
import { _set } from './packages/common/dist/esm/utils/set.js'; | ||
import { deepSet } from './packages/common/dist/esm/utils/deepSet.js'; | ||
@@ -68,2 +69,11 @@ import { executeValidation } from './packages/common/dist/esm/utils/executeValidation.js'; | ||
function unsetField(path) { | ||
data.update(($data) => { | ||
const newData = _unset($data, path); | ||
if (formNode) | ||
setForm(formNode, newData); | ||
return newData; | ||
}); | ||
touched.update(($touched) => { | ||
return _unset($touched, path); | ||
}); | ||
errors.update(($errors) => { | ||
@@ -75,11 +85,2 @@ return _unset($errors, path); | ||
}); | ||
touched.update(($touched) => { | ||
return _unset($touched, path); | ||
}); | ||
data.update(($data) => { | ||
const newData = _unset($data, path); | ||
if (formNode) | ||
setForm(formNode, newData); | ||
return newData; | ||
}); | ||
} | ||
@@ -123,10 +124,14 @@ function addField(path, value, index) { | ||
async function validate() { | ||
const validate = getAllValidators('validate', config); | ||
const warn = getAllValidators('warn', config); | ||
const currentData = get(data); | ||
const initialErrors = deepSet(currentData, null); | ||
setTouched((t) => { | ||
return deepSet(t, true); | ||
}); | ||
const currentErrors = await executeValidation(currentData, config.validate); | ||
const currentWarnings = await executeValidation(currentData, config.warn); | ||
warnings.set(_merge(deepSet(currentData, null), currentWarnings || {})); | ||
errors.set(currentErrors || {}); | ||
const partialErrors = await executeValidation(currentData, validate); | ||
const currentErrors = _merge(initialErrors, partialErrors); | ||
const currentWarnings = await executeValidation(currentData, warn); | ||
warnings.set(_merge(initialErrors, currentWarnings || {})); | ||
errors.set(currentErrors || initialErrors); | ||
return currentErrors; | ||
@@ -141,28 +146,30 @@ } | ||
} | ||
return { | ||
public: { | ||
setData, | ||
setFields, | ||
setTouched, | ||
setErrors, | ||
setWarnings, | ||
setIsSubmitting, | ||
setIsDirty, | ||
validate, | ||
reset, | ||
unsetField, | ||
resetField, | ||
addField, | ||
setInitialValues: (values) => { | ||
initialValues = values; | ||
}, | ||
const publicHelpers = { | ||
setData, | ||
setFields, | ||
setTouched, | ||
setErrors, | ||
setWarnings, | ||
setIsSubmitting, | ||
setIsDirty, | ||
validate, | ||
reset, | ||
unsetField, | ||
resetField, | ||
addField, | ||
setInitialValues: (values) => { | ||
initialValues = values; | ||
}, | ||
private: { | ||
_setFormNode: (node) => { | ||
formNode = node; | ||
}, | ||
_getFormNode: () => formNode, | ||
_getInitialValues: () => initialValues, | ||
}; | ||
const privateHelpers = { | ||
_setFormNode: (node) => { | ||
formNode = node; | ||
}, | ||
_getFormNode: () => formNode, | ||
_getInitialValues: () => initialValues, | ||
}; | ||
return { | ||
public: publicHelpers, | ||
private: privateHelpers, | ||
}; | ||
} | ||
@@ -169,0 +176,0 @@ |
@@ -24,5 +24,5 @@ export { get as getValueFromStore } from './get.js'; | ||
export { getValue } from './packages/common/dist/esm/utils/getValue.js'; | ||
export { executeValidation } from './packages/common/dist/esm/utils/executeValidation.js'; | ||
export { executeValidation, mergeErrors, runValidations } from './packages/common/dist/esm/utils/executeValidation.js'; | ||
export { executeTransforms } from './packages/common/dist/esm/utils/executeTransforms.js'; | ||
export { addAttrsFromFieldset, getFormControls, getFormDefaultValues, getInputTextOrNumber, setControlValue, setForm } from './packages/common/dist/esm/utils/domUtils.js'; | ||
//# sourceMappingURL=index.js.map |
@@ -7,5 +7,5 @@ import { _mergeWith } from './mergeWith.js'; | ||
return; | ||
if (objValue === null) | ||
if (objValue === null || objValue === '') | ||
return srcValue; | ||
if (srcValue === null) | ||
if (srcValue === null || srcValue === '') | ||
return objValue; | ||
@@ -20,12 +20,19 @@ if (!objValue || !srcValue) | ||
} | ||
function mergeErrors(errors) { | ||
return _mergeWith(...errors, executeCustomizer); | ||
} | ||
function runValidations(values, validationOrValidations) { | ||
if (!validationOrValidations) | ||
return []; | ||
const validations = Array.isArray(validationOrValidations) | ||
? validationOrValidations | ||
: [validationOrValidations]; | ||
return validations.map((v) => v(values)); | ||
} | ||
async function executeValidation(values, validations) { | ||
if (!validations) | ||
return; | ||
if (!Array.isArray(validations)) | ||
return validations(values); | ||
const errorArray = await Promise.all(validations.map((v) => v(values))); | ||
return _mergeWith(...errorArray, executeCustomizer); | ||
const errors = await Promise.all(runValidations(values, validations)); | ||
return mergeErrors(errors); | ||
} | ||
export { executeValidation }; | ||
export { executeValidation, mergeErrors, runValidations }; | ||
//# sourceMappingURL=executeValidation.js.map |
import { executeTransforms } from './packages/common/dist/esm/utils/executeTransforms.js'; | ||
import { _cloneDeep } from './packages/common/dist/esm/utils/cloneDeep.js'; | ||
import { deepSet } from './packages/common/dist/esm/utils/deepSet.js'; | ||
import { mergeErrors, runValidations } from './packages/common/dist/esm/utils/executeValidation.js'; | ||
import { deepSome } from './packages/common/dist/esm/utils/deepSome.js'; | ||
import { _mergeWith } from './packages/common/dist/esm/utils/mergeWith.js'; | ||
import { _isPlainObject } from './packages/common/dist/esm/utils/isPlainObject.js'; | ||
import { executeValidation } from './packages/common/dist/esm/utils/executeValidation.js'; | ||
import { _merge } from './packages/common/dist/esm/utils/merge.js'; | ||
function createAbortController() { | ||
const signal = { aborted: false }; | ||
return { | ||
signal, | ||
abort() { | ||
signal.aborted = true; | ||
}, | ||
}; | ||
} | ||
function errorFilterer(errValue, touchValue) { | ||
@@ -21,3 +29,67 @@ if (_isPlainObject(touchValue)) | ||
} | ||
function filterErrors([errors, touched]) { | ||
return _mergeWith(errors, touched, errorFilterer); | ||
} | ||
function debounce(func, timeout = 300) { | ||
let timer; | ||
return (...args) => { | ||
clearTimeout(timer); | ||
timer = setTimeout(() => { | ||
func.apply(this, args); | ||
}, timeout); | ||
}; | ||
} | ||
function cancellableValidation(store) { | ||
let activeController; | ||
return async function executeValidations($data, validations) { | ||
if (!validations || !$data) | ||
return; | ||
let current = deepSet($data, null); | ||
const controller = createAbortController(); | ||
if (activeController) | ||
activeController.abort(); | ||
activeController = controller; | ||
const results = runValidations($data, validations); | ||
results.forEach(async (promise) => { | ||
const result = await promise; | ||
if (controller.signal.aborted) | ||
return; | ||
current = mergeErrors([current, result]); | ||
store.set(current); | ||
}); | ||
}; | ||
} | ||
function createDerivedFactory(storeFactory) { | ||
return function derived(storeOrStores, deriver, initialValue) { | ||
const stores = Array.isArray(storeOrStores) | ||
? storeOrStores | ||
: [storeOrStores]; | ||
const values = new Array(stores.length); | ||
const derivedStore = storeFactory(initialValue); | ||
const storeSet = derivedStore.set; | ||
const storeSubscribe = derivedStore.subscribe; | ||
let unsubscribers; | ||
function startStore() { | ||
unsubscribers = stores.map((store, index) => { | ||
return store.subscribe(($store) => { | ||
values[index] = $store; | ||
storeSet(deriver(values)); | ||
}); | ||
}); | ||
} | ||
function stopStore() { | ||
unsubscribers === null || unsubscribers === void 0 ? void 0 : unsubscribers.forEach((unsub) => unsub()); | ||
} | ||
derivedStore.subscribe = function subscribe(subscriber) { | ||
const unsubscribe = storeSubscribe(subscriber); | ||
return () => { | ||
unsubscribe(); | ||
}; | ||
}; | ||
return [derivedStore, startStore, stopStore]; | ||
}; | ||
} | ||
function createStores(storeFactory, config) { | ||
var _a, _b, _c, _d, _e, _f, _g; | ||
const derived = createDerivedFactory(storeFactory); | ||
const initialValues = config.initialValues | ||
@@ -28,65 +100,69 @@ ? executeTransforms(_cloneDeep(config.initialValues), config.transform) | ||
const initialErrors = deepSet(initialValues, null); | ||
const errors = storeFactory(initialErrors); | ||
const filteredErrors = storeFactory(_cloneDeep(initialErrors)); | ||
const filteredErrorsSet = filteredErrors.set; | ||
const immediateErrors = storeFactory(initialErrors); | ||
const debouncedErrors = storeFactory(_cloneDeep(initialErrors)); | ||
const [errors, startErrors, stopErrors] = derived([ | ||
immediateErrors, | ||
debouncedErrors, | ||
], mergeErrors, _cloneDeep(initialErrors)); | ||
const initialWarnings = deepSet(initialValues, null); | ||
const warnings = storeFactory(initialWarnings); | ||
const immediateWarnings = storeFactory(initialWarnings); | ||
const debouncedWarnings = storeFactory(_cloneDeep(initialWarnings)); | ||
const [warnings, startWarnings, stopWarnings] = derived([ | ||
immediateWarnings, | ||
debouncedWarnings, | ||
], mergeErrors, _cloneDeep(initialWarnings)); | ||
const initialTouched = deepSet(initialValues, false); | ||
const touched = storeFactory(initialTouched); | ||
const isValid = storeFactory(!config.validate); | ||
const [filteredErrors, startFilteredErrors, stopFilteredErrors] = derived([errors, touched], filterErrors, _cloneDeep(initialErrors)); | ||
let firstCalled = false; | ||
const [isValid, startIsValid, stopIsValid] = derived(errors, ([$errors]) => { | ||
var _a; | ||
if (!firstCalled) { | ||
firstCalled = true; | ||
return !config.validate && !((_a = config.debounced) === null || _a === void 0 ? void 0 : _a.validate); | ||
} | ||
else { | ||
return !deepSome($errors, (error) => !!error); | ||
} | ||
}, !config.validate && !((_a = config.debounced) === null || _a === void 0 ? void 0 : _a.validate)); | ||
delete isValid.set; | ||
delete isValid.update; | ||
const isSubmitting = storeFactory(false); | ||
const isDirty = storeFactory(false); | ||
async function validateErrors($data) { | ||
let currentErrors = {}; | ||
if (!config.validate || !$data) | ||
return; | ||
currentErrors = await executeValidation($data, config.validate); | ||
errors.set(currentErrors || {}); | ||
} | ||
async function validateWarnings($data) { | ||
let currentWarnings = {}; | ||
if (!config.warn || !$data) | ||
return; | ||
currentWarnings = await executeValidation($data, config.warn); | ||
warnings.set(_merge(deepSet($data, null), currentWarnings || {})); | ||
} | ||
const validateErrors = cancellableValidation(immediateErrors); | ||
const validateWarnings = cancellableValidation(immediateWarnings); | ||
const validateDebouncedErrors = debounce(cancellableValidation(debouncedErrors), (_c = (_b = config.debounced) === null || _b === void 0 ? void 0 : _b.validateTimeout) !== null && _c !== void 0 ? _c : (_d = config.debounced) === null || _d === void 0 ? void 0 : _d.timeout); | ||
const validateDebouncedWarnings = debounce(cancellableValidation(debouncedWarnings), (_f = (_e = config.debounced) === null || _e === void 0 ? void 0 : _e.warnTimeout) !== null && _f !== void 0 ? _f : (_g = config.debounced) === null || _g === void 0 ? void 0 : _g.timeout); | ||
function start() { | ||
const dataUnsubscriber = data.subscribe(($data) => { | ||
validateErrors($data); | ||
validateWarnings($data); | ||
var _a, _b; | ||
validateErrors($data, config.validate); | ||
validateWarnings($data, config.warn); | ||
debouncedErrors.set({}); | ||
validateDebouncedErrors($data, (_a = config.debounced) === null || _a === void 0 ? void 0 : _a.validate); | ||
debouncedWarnings.set({}); | ||
validateDebouncedWarnings($data, (_b = config.debounced) === null || _b === void 0 ? void 0 : _b.warn); | ||
}); | ||
let touchedValue = initialTouched; | ||
let errorsValue = initialErrors; | ||
let firstCalled = false; | ||
const errorsUnsubscriber = errors.subscribe(($errors) => { | ||
if (!firstCalled) { | ||
firstCalled = true; | ||
isValid.set(!config.validate); | ||
} | ||
else { | ||
const hasErrors = deepSome($errors, (error) => !!error); | ||
isValid.set(!hasErrors); | ||
} | ||
errorsValue = $errors; | ||
const mergedErrors = _mergeWith($errors, touchedValue, errorFilterer); | ||
filteredErrorsSet(mergedErrors); | ||
}); | ||
const touchedUnsubscriber = touched.subscribe(($touched) => { | ||
touchedValue = $touched; | ||
const mergedErrors = _mergeWith(errorsValue, $touched, errorFilterer); | ||
filteredErrorsSet(mergedErrors); | ||
}); | ||
startErrors(); | ||
startIsValid(); | ||
startWarnings(); | ||
startFilteredErrors(); | ||
function cleanup() { | ||
dataUnsubscriber(); | ||
errorsUnsubscriber(); | ||
touchedUnsubscriber(); | ||
stopFilteredErrors(); | ||
stopErrors(); | ||
stopWarnings(); | ||
stopIsValid(); | ||
} | ||
return cleanup; | ||
} | ||
filteredErrors.set = errors.set; | ||
filteredErrors.update = errors.update; | ||
filteredErrors.set = immediateErrors.set; | ||
filteredErrors.update = | ||
immediateErrors.update; | ||
warnings.set = immediateWarnings.set; | ||
warnings.update = immediateWarnings.update; | ||
return { | ||
data, | ||
errors: filteredErrors, | ||
warnings, | ||
warnings: warnings, | ||
touched, | ||
@@ -101,3 +177,3 @@ isValid, | ||
export { createStores }; | ||
export { createDerivedFactory, createStores }; | ||
//# sourceMappingURL=stores.js.map |
@@ -1,9 +0,8 @@ | ||
import { Extender, Obj, Stores, FormConfig, ValidationFunction, TransformFunction, ExtenderHandler, CreateSubmitHandlerConfig, Helpers } from '@felte/common'; | ||
type Configuration<Data extends Obj> = { | ||
import { Extender, Obj, Stores, FormConfig, TransformFunction, ExtenderHandler, CreateSubmitHandlerConfig, AddValidatorFn, Helpers } from '@felte/common'; | ||
type FormActionConfig<Data extends Obj> = { | ||
stores: Stores<Data>; | ||
config: FormConfig<Data>; | ||
extender: Extender<Data>[]; | ||
helpers: Helpers<Data> & { | ||
addValidator(validator: ValidationFunction<Data>): void; | ||
addWarnValidator(validator: ValidationFunction<Data>): void; | ||
helpers: Helpers<Data, string> & { | ||
addValidator: AddValidatorFn<Data>; | ||
addTransformer(transformer: TransformFunction<Data>): void; | ||
@@ -17,3 +16,3 @@ }; | ||
}; | ||
declare function createFormAction<Data extends Obj>({ helpers, stores, config, extender, _setFormNode, _getFormNode, _getInitialValues, _setCurrentExtenders, _getCurrentExtenders, }: Configuration<Data>): { | ||
declare function createFormAction<Data extends Obj>({ helpers, stores, config, extender, _setFormNode, _getFormNode, _getInitialValues, _setCurrentExtenders, _getCurrentExtenders, }: FormActionConfig<Data>): { | ||
form: (node: HTMLFormElement) => { | ||
@@ -25,2 +24,2 @@ destroy(): void; | ||
}; | ||
export { createFormAction }; | ||
export { FormActionConfig, createFormAction }; |
@@ -1,2 +0,2 @@ | ||
import { Errors, Extender, FieldValue, FormConfig, Obj, Stores, Touched, ValidationFunction, TransformFunction, ObjectSetter, PrimitiveSetter } from '@felte/common'; | ||
import { Extender, FormConfig, Obj, Stores, ValidationFunction, TransformFunction, Helpers } from '@felte/common'; | ||
type CreateHelpersOptions<Data extends Obj> = { | ||
@@ -10,17 +10,3 @@ config: FormConfig<Data>; | ||
declare function createHelpers<Data extends Obj>({ stores, config, }: CreateHelpersOptions<Data>): { | ||
public: { | ||
setData: ObjectSetter<Data, FieldValue | FieldValue[]>; | ||
setFields: (pathOrValue: string | Data | ((value: Data) => Data), valueOrUpdater?: (FieldValue | FieldValue[]) | ((value: FieldValue | FieldValue[]) => FieldValue | FieldValue[]), shouldTouch?: boolean | undefined) => void; | ||
setTouched: ObjectSetter<Touched<Data>, boolean>; | ||
setErrors: ObjectSetter<Errors<Data>, string | string[]>; | ||
setWarnings: ObjectSetter<Errors<Data>, string | string[]>; | ||
setIsSubmitting: PrimitiveSetter<boolean>; | ||
setIsDirty: PrimitiveSetter<boolean>; | ||
validate: () => Promise<Errors<Data> | void>; | ||
reset: () => void; | ||
unsetField: (path: string) => void; | ||
resetField: (path: string) => void; | ||
addField: (path: string, value: FieldValue | FieldValue[], index?: number | undefined) => void; | ||
setInitialValues: (values: Data) => void; | ||
}; | ||
public: Helpers<Data, string>; | ||
private: { | ||
@@ -27,0 +13,0 @@ _setFormNode: (node: HTMLFormElement) => void; |
@@ -1,15 +0,27 @@ | ||
import { StoreFactory, Obj, FormConfig, Errors, Touched } from '@felte/common'; | ||
import { StoreFactory, Obj, FormConfig, Errors, Touched, PartialWritable } from '@felte/common'; | ||
import { Writable, Readable } from 'svelte/store'; | ||
type Readables = Readable<any> | [Readable<any>, ...Array<Readable<any>>] | Array<Readable<any>>; | ||
type ReadableValues<T> = T extends Readable<infer U> ? [U] : { | ||
[K in keyof T]: T[K] extends Readable<infer U> ? U : never; | ||
}; | ||
declare function createDerivedFactory<StoreExt = Record<string, any>>(storeFactory: StoreFactory<StoreExt>): <R, T extends Readables = Readables>(storeOrStores: T, deriver: (values: ReadableValues<T>) => R, initialValue: R) => [Readable<R> & { | ||
update?: ((updater: (v: R) => R) => void) | undefined; | ||
set?: ((v: R) => void) | undefined; | ||
} & StoreExt, () => void, () => void]; | ||
declare function createStores<Data extends Obj, StoreExt = Record<string, any>>(storeFactory: StoreFactory<StoreExt>, config: FormConfig<Data> & { | ||
preventStoreStart?: boolean; | ||
}): { | ||
data: import("svelte/store").Writable<Data> & StoreExt; | ||
errors: import("svelte/store").Writable<Errors<Data>> & StoreExt; | ||
warnings: import("svelte/store").Writable<Errors<Data>> & StoreExt; | ||
touched: import("svelte/store").Writable<Touched<Data>> & StoreExt; | ||
isValid: import("svelte/store").Writable<boolean> & StoreExt; | ||
isSubmitting: import("svelte/store").Writable<boolean> & StoreExt; | ||
isDirty: import("svelte/store").Writable<boolean> & StoreExt; | ||
data: Writable<Data> & StoreExt; | ||
errors: PartialWritable<Errors<Data>> & StoreExt; | ||
warnings: PartialWritable<Errors<Data>> & StoreExt; | ||
touched: Writable<Touched<Data>> & StoreExt; | ||
isValid: Readable<boolean> & { | ||
update?: ((updater: (v: boolean) => boolean) => void) | undefined; | ||
set?: ((v: boolean) => void) | undefined; | ||
} & StoreExt; | ||
isSubmitting: Writable<boolean> & StoreExt; | ||
isDirty: Writable<boolean> & StoreExt; | ||
cleanup: () => void; | ||
start: () => () => void; | ||
}; | ||
export { createStores }; | ||
export { createDerivedFactory, createStores }; |
{ | ||
"name": "@felte/core", | ||
"version": "1.0.0-next.13", | ||
"version": "1.0.0-next.14", | ||
"description": "Core package for FelteJS", | ||
@@ -27,3 +27,3 @@ "main": "dist/cjs/index.js", | ||
"dependencies": { | ||
"@felte/common": "1.0.0-next.10" | ||
"@felte/common": "1.0.0-next.11" | ||
}, | ||
@@ -30,0 +30,0 @@ "publishConfig": { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
341194
79
2970
+ Added@felte/common@1.0.0-next.11(transitive)
- Removed@felte/common@1.0.0-next.10(transitive)
Updated@felte/common@1.0.0-next.11