@shopify/react-form
Advanced tools
Comparing version 0.0.0-snapshot-20240308174203 to 0.0.0-snapshot-20240620045713
@@ -111,3 +111,2 @@ 'use strict'; | ||
const errors = validators.map(check => check(value, {})).filter(value => value != null); | ||
if (errors && errors.length > 0) { | ||
@@ -118,6 +117,6 @@ const [firstError] = errors; | ||
} | ||
dispatch(reducer.updateErrorAction(undefined)); | ||
return undefined; | ||
}, // eslint-disable-next-line react-hooks/exhaustive-deps | ||
}, | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
[state.value, ...dependencies]); | ||
@@ -127,3 +126,2 @@ const onChange = react.useCallback(value => { | ||
dispatch(reducer.updateAction(normalizedValue)); | ||
if (state.error) { | ||
@@ -138,17 +136,18 @@ runValidation(normalizedValue); | ||
} | ||
runValidation(); | ||
}, [runValidation, state.touched, state.error]); // We want to reset the field whenever a new `value` is passed in | ||
}, [runValidation, state.touched, state.error]); | ||
// We want to reset the field whenever a new `value` is passed in | ||
react.useEffect(() => { | ||
if (!isEqual__default["default"](value, state.defaultValue)) { | ||
newDefaultValue(value); | ||
} // We actually do not want this to rerun when our `defaultValue` is updated. It can | ||
} | ||
// We actually do not want this to rerun when our `defaultValue` is updated. It can | ||
// only happen independently of this callback when `newDefaultValue` is called by a user, | ||
// and we don't want to undue their hard work by resetting to `value`. | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
}, [value, newDefaultValue]); | ||
const field = react.useMemo(() => { | ||
return { ...state, | ||
return { | ||
...state, | ||
onBlur, | ||
@@ -164,3 +163,2 @@ onChange, | ||
} | ||
/** | ||
@@ -192,5 +190,5 @@ * Converts a standard `Field<Value>` into a `ChoiceField` that is compatible | ||
}, checkedValue = true) { | ||
return { ...fieldData, | ||
return { | ||
...fieldData, | ||
checked: value === checkedValue, | ||
onChange(checked) { | ||
@@ -203,5 +201,5 @@ if (typeof checkedValue === 'boolean') { | ||
} | ||
}; | ||
} | ||
/** | ||
@@ -229,3 +227,2 @@ * Converts a standard `Field<Value>` into a form that is compatible | ||
*/ | ||
function asChoiceList({ | ||
@@ -236,3 +233,4 @@ value, | ||
}) { | ||
return { ...fieldData, | ||
return { | ||
...fieldData, | ||
selected: value === undefined || value === null ? [] : [value], | ||
@@ -245,2 +243,3 @@ onChange: selected => { | ||
} | ||
/** | ||
@@ -256,7 +255,5 @@ * A simplification to `useField` that returns a `ChoiceField` by automatically | ||
*/ | ||
function useChoiceField(input, dependencies = []) { | ||
return asChoiceField(useField(input, dependencies)); | ||
} | ||
function normalizeFieldConfig(input) { | ||
@@ -266,3 +263,2 @@ if (isFieldConfig(input)) { | ||
} | ||
return { | ||
@@ -273,3 +269,2 @@ value: input, | ||
} | ||
function isFieldConfig(input) { | ||
@@ -276,0 +271,0 @@ return input != null && typeof input === 'object' && Reflect.has(input, 'value') && Reflect.has(input, 'validates'); |
@@ -49,3 +49,4 @@ 'use strict'; | ||
const dirty = dirtyStateComparator(defaultValue, newValue); | ||
return { ...state, | ||
return { | ||
...state, | ||
dirty, | ||
@@ -56,3 +57,2 @@ value: newValue, | ||
} | ||
case 'updateError': | ||
@@ -63,9 +63,10 @@ { | ||
const allErrors = firstError ? payload : []; | ||
if (utilities.shallowArrayComparison(allErrors, state.allErrors)) { | ||
return { ...state, | ||
return { | ||
...state, | ||
error: firstError | ||
}; | ||
} else { | ||
return { ...state, | ||
return { | ||
...state, | ||
error: firstError, | ||
@@ -76,3 +77,2 @@ allErrors | ||
} | ||
case 'reset': | ||
@@ -83,3 +83,4 @@ { | ||
} = state; | ||
return { ...state, | ||
return { | ||
...state, | ||
error: undefined, | ||
@@ -92,7 +93,7 @@ value: defaultValue, | ||
} | ||
case 'newDefaultValue': | ||
{ | ||
const newDefaultValue = action.payload; | ||
return { ...state, | ||
return { | ||
...state, | ||
error: undefined, | ||
@@ -99,0 +100,0 @@ value: newDefaultValue, |
@@ -74,3 +74,4 @@ 'use strict'; | ||
if (dynamicLists) { | ||
const fieldsWithList = { ...fields | ||
const fieldsWithList = { | ||
...fields | ||
}; | ||
@@ -82,3 +83,2 @@ Object.entries(dynamicLists).forEach(([key, value]) => { | ||
} | ||
return fields; | ||
@@ -121,9 +121,8 @@ }, [dynamicLists, fields]); | ||
}; | ||
if (dynamicLists) { | ||
return { ...form, | ||
return { | ||
...form, | ||
dynamicLists | ||
}; | ||
} | ||
return form; | ||
@@ -130,0 +129,0 @@ } |
@@ -43,16 +43,14 @@ 'use strict'; | ||
dispatch(reducer.reinitializeAction(list)); | ||
} // eslint-disable-next-line react-hooks/exhaustive-deps | ||
} | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
}, [list, dispatch]); | ||
const validationConfigs = react.useMemo(() => utilities.mapObject(validates, utilities.normalizeValidation), // eslint-disable-next-line react-hooks/exhaustive-deps | ||
const validationConfigs = react.useMemo(() => utilities.mapObject(validates, utilities.normalizeValidation), | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
[validates, ...validationDependencies]); | ||
function reset() { | ||
dispatch(reducer.resetListAction()); | ||
} | ||
function newDefaultValue(newDefaultItems) { | ||
dispatch(reducer.reinitializeAction(newDefaultItems)); | ||
} | ||
const handlers$1 = handlers.useHandlers(state, dispatch, validationConfigs); | ||
@@ -62,3 +60,4 @@ const fields = react.useMemo(() => { | ||
return utilities.mapObject(item, (field, key) => { | ||
return { ...field, | ||
return { | ||
...field, | ||
...handlers$1[index][key] | ||
@@ -65,0 +64,0 @@ }; |
@@ -16,2 +16,3 @@ 'use strict'; | ||
*/ | ||
function useDynamicList(listOrConfig, fieldFactory, validationDependencies = []) { | ||
@@ -27,6 +28,4 @@ const { | ||
} = baselist.useBaseList(listOrConfig, validationDependencies); | ||
function addItem(factoryArgument) { | ||
const itemToAdd = fieldFactory(factoryArgument); | ||
if (Array.isArray(itemToAdd)) { | ||
@@ -38,19 +37,14 @@ dispatch(reducer.addFieldItemAction(itemToAdd)); | ||
} | ||
function editItem(editedItem, index) { | ||
dispatch(reducer.editFieldItemAction(editedItem, index)); | ||
} | ||
function moveItem(fromIndex, toIndex) { | ||
dispatch(reducer.moveFieldItemAction(fromIndex, toIndex)); | ||
} | ||
function removeItem(index) { | ||
dispatch(reducer.removeFieldItemAction(index)); | ||
} | ||
function removeItems(indicesToRemove) { | ||
dispatch(reducer.removeFieldItemsAction(indicesToRemove)); | ||
} | ||
return { | ||
@@ -57,0 +51,0 @@ fields, |
@@ -15,3 +15,2 @@ 'use strict'; | ||
} | ||
function resetFields(lists) { | ||
@@ -18,0 +17,0 @@ if (lists) { |
@@ -18,10 +18,7 @@ 'use strict'; | ||
}; | ||
function validate(value = field.value) { | ||
const validates = validationConfigs[key]; | ||
if (validates == null) { | ||
return; | ||
} | ||
const siblings = state.list.filter(listItem => listItem !== item); | ||
@@ -37,3 +34,2 @@ return utils.runValidation(error => dispatch(reducer.updateErrorAction({ | ||
} | ||
return { | ||
@@ -46,3 +42,2 @@ onChange(value) { | ||
})); | ||
if (field.error) { | ||
@@ -52,3 +47,2 @@ validate(normalizedValue); | ||
}, | ||
reset() { | ||
@@ -59,3 +53,2 @@ dispatch(reducer.resetAction({ | ||
}, | ||
newDefaultValue(value) { | ||
@@ -67,5 +60,3 @@ dispatch(reducer.newDefaultAction({ | ||
}, | ||
runValidation: validate, | ||
onBlur() { | ||
@@ -76,10 +67,7 @@ const { | ||
} = field; | ||
if (touched === false && error == null) { | ||
return; | ||
} | ||
validate(); | ||
}, | ||
setError(error) { | ||
@@ -91,3 +79,2 @@ dispatch(reducer.updateErrorAction({ | ||
} | ||
}; | ||
@@ -94,0 +81,0 @@ }); |
@@ -94,3 +94,2 @@ 'use strict'; | ||
} | ||
function reduceList(state, action) { | ||
@@ -105,3 +104,2 @@ switch (action.type) { | ||
} | ||
case 'moveFieldItem': | ||
@@ -113,39 +111,38 @@ { | ||
} = action.payload; | ||
if (fromIndex >= state.list.length || fromIndex < 0 || toIndex >= state.list.length || toIndex < 0) { | ||
throw new Error(`Failed to move item from ${fromIndex} to ${toIndex}`); | ||
} | ||
const newList = [...state.list]; | ||
const [item] = newList.splice(action.payload.fromIndex, 1); | ||
newList.splice(action.payload.toIndex, 0, item); | ||
return { ...state, | ||
return { | ||
...state, | ||
list: newList | ||
}; | ||
} | ||
case 'addFieldItem': | ||
{ | ||
return { ...state, | ||
return { | ||
...state, | ||
list: [...state.list, ...action.payload.list.map(initialListItemState)] | ||
}; | ||
} | ||
case 'editFieldItem': | ||
{ | ||
var _state$list, _state$list$map; | ||
const { | ||
editedItem, | ||
index | ||
} = action.payload; // Don't do a full rewrite of the object, only edit data which is supplied. | ||
} = action.payload; | ||
const list = state === null || state === void 0 ? void 0 : (_state$list = state.list) === null || _state$list === void 0 ? void 0 : (_state$list$map = _state$list.map) === null || _state$list$map === void 0 ? void 0 : _state$list$map.call(_state$list, (item, i) => i === index ? { ...item, | ||
// Don't do a full rewrite of the object, only edit data which is supplied. | ||
const list = state === null || state === void 0 || (_state$list = state.list) === null || _state$list === void 0 || (_state$list$map = _state$list.map) === null || _state$list$map === void 0 ? void 0 : _state$list$map.call(_state$list, (item, i) => i === index ? { | ||
...item, | ||
...editedItem | ||
} : item); | ||
return { ...state, | ||
return { | ||
...state, | ||
list | ||
}; | ||
} | ||
case 'removeFieldItem': | ||
@@ -155,18 +152,17 @@ { | ||
newList.splice(action.payload.indexToRemove, 1); | ||
return { ...state, | ||
return { | ||
...state, | ||
list: newList | ||
}; | ||
} | ||
case 'removeFieldItems': | ||
{ | ||
var _action$payload$indic, _action$payload; | ||
const indicesToRemove = (_action$payload$indic = action === null || action === void 0 ? void 0 : (_action$payload = action.payload) === null || _action$payload === void 0 ? void 0 : _action$payload.indicesToRemove) !== null && _action$payload$indic !== void 0 ? _action$payload$indic : []; | ||
const indicesToRemove = (_action$payload$indic = action === null || action === void 0 || (_action$payload = action.payload) === null || _action$payload === void 0 ? void 0 : _action$payload.indicesToRemove) !== null && _action$payload$indic !== void 0 ? _action$payload$indic : []; | ||
const list = state.list.filter((_, i) => !indicesToRemove.includes(i)); | ||
return { ...state, | ||
return { | ||
...state, | ||
list | ||
}; | ||
} | ||
case 'updateError': | ||
@@ -186,7 +182,7 @@ { | ||
currentItem[key] = reducer.reduceField(currentItem[key], reducer.updateErrorAction(error)); | ||
return { ...state, | ||
return { | ||
...state, | ||
list: [...state.list] | ||
}; | ||
} | ||
case 'reset': | ||
@@ -207,14 +203,14 @@ { | ||
}); | ||
return { ...state, | ||
return { | ||
...state, | ||
list: [...state.list] | ||
}; | ||
} | ||
case 'resetList': | ||
{ | ||
return { ...state, | ||
return { | ||
...state, | ||
list: state.initial.map(initialListItemState) | ||
}; | ||
} | ||
case 'update': | ||
@@ -238,3 +234,4 @@ case 'newDefaultValue': | ||
}); | ||
return { ...state, | ||
return { | ||
...state, | ||
list: [...state.list] | ||
@@ -245,3 +242,2 @@ }; | ||
} | ||
function initialListItemState(item) { | ||
@@ -248,0 +244,0 @@ return utilities.mapObject(item, reducer.initialFieldState); |
@@ -102,3 +102,2 @@ 'use strict'; | ||
*/ | ||
function useList(listOrConfig, validationDependencies = []) { | ||
@@ -105,0 +104,0 @@ const { |
@@ -15,3 +15,2 @@ 'use strict'; | ||
})).filter(value => value != null); | ||
if (error && error.length > 0) { | ||
@@ -22,3 +21,2 @@ const [firstError] = error; | ||
} | ||
updateError(undefined); | ||
@@ -25,0 +23,0 @@ return undefined; |
@@ -10,3 +10,2 @@ 'use strict'; | ||
} | ||
function resetField(field) { | ||
@@ -13,0 +12,0 @@ field.reset(); |
@@ -23,9 +23,6 @@ 'use strict'; | ||
const dynamicLists = dynamicListBagRef.current; | ||
if (event && event.preventDefault && !event.defaultPrevented) { | ||
event.preventDefault(); | ||
} | ||
const clientErrors = utilities.validateAll(fields); | ||
if (clientErrors.length > 0) { | ||
@@ -35,12 +32,8 @@ setErrors(clientErrors); | ||
} | ||
setSubmitting(true); | ||
const result = await onSubmit(utilities.getValues(fields)); | ||
if (mounted.current === false) { | ||
return; | ||
} | ||
setSubmitting(false); | ||
if (result.status === 'fail') { | ||
@@ -50,3 +43,2 @@ setErrors(result.errors); | ||
setSubmitErrors([]); | ||
if (makeCleanAfterSubmit) { | ||
@@ -65,2 +57,3 @@ utilities.makeCleanFields(fields); | ||
} | ||
/** | ||
@@ -70,3 +63,2 @@ * A convenience function for `onSubmit` callbacks returning values to `useSubmit` or `useForm`. | ||
*/ | ||
function submitSuccess() { | ||
@@ -77,2 +69,3 @@ return { | ||
} | ||
/** | ||
@@ -83,3 +76,2 @@ * A convenience function for `onSubmit` callbacks returning values to `useSubmit` or `useForm` | ||
*/ | ||
function submitFail(errors = []) { | ||
@@ -91,3 +83,2 @@ return { | ||
} | ||
function noopSubmission(_) { | ||
@@ -94,0 +85,0 @@ return Promise.resolve(submitSuccess()); |
@@ -20,17 +20,16 @@ 'use strict'; | ||
}, {}); | ||
} // Eg: set({a: 1}, ['b', 'c'], 2) // => {a: 1, b: {c: 2}} | ||
} | ||
// Eg: set({a: 1}, ['b', 'c'], 2) // => {a: 1, b: {c: 2}} | ||
function setObject(obj, path, value) { | ||
const [key, ...restPath] = path; | ||
if (key == null || obj === null || typeof obj !== 'object') { | ||
return obj; | ||
} | ||
if (!restPath.length) { | ||
obj[key] = value; | ||
return obj; | ||
} // creates prop if it doesn't exist | ||
} | ||
// creates prop if it doesn't exist | ||
if (typeof obj[key] === 'undefined') { | ||
@@ -40,7 +39,5 @@ // look ahead to the next key. If it is a number, this prop is an array | ||
} | ||
obj[key] = setObject(obj[key], restPath, value); | ||
return obj; | ||
} | ||
function normalizeValidation(input) { | ||
@@ -57,5 +54,3 @@ return Array.isArray(input) ? input : [input]; | ||
} | ||
const got = get__default["default"](fieldBag, error.field); | ||
if (got && isField(got)) { | ||
@@ -67,4 +62,5 @@ if (got.error !== error.message) { | ||
}); | ||
} // Reduce function similar to Array.reduce() for a tree-like FieldBag | ||
} | ||
// Reduce function similar to Array.reduce() for a tree-like FieldBag | ||
function reduceFields(fieldBag, reduceFn, initialValue, reduceEmptyFn = value => value) { | ||
@@ -75,16 +71,13 @@ return function reduceField(accumulator, item, path) { | ||
} | ||
if (Array.isArray(item) && item.length) { | ||
return item.reduce((_accumulator, value, index) => reduceField(_accumulator, value, path.concat(index)), accumulator); | ||
} | ||
if (typeof item === 'object' && item !== null) { | ||
const entries = Object.entries(item); | ||
if (entries.length) { | ||
return entries.reduce((_accumulator, [key, value]) => reduceField(_accumulator, value, path.concat(key)), accumulator); | ||
} | ||
} // item is empty array, empty object, or primitive | ||
} | ||
// item is empty array, empty object, or primitive | ||
return reduceEmptyFn(accumulator, item, path, fieldBag); | ||
@@ -111,3 +104,4 @@ }(initialValue, fieldBag, []); | ||
const dirtyArray = field.map(dirtyField => Object.entries(dirtyField).reduce(reduceFn, {})).filter(dirtyField => Object.keys(dirtyField).length); | ||
return { ...acc, | ||
return { | ||
...acc, | ||
...(dirtyArray.length ? { | ||
@@ -118,6 +112,6 @@ [fieldName]: dirtyArray | ||
} | ||
if (!isField(field)) { | ||
const dirtyField = Object.entries(field).reduce(reduceFn, {}); | ||
return { ...acc, | ||
return { | ||
...acc, | ||
...(Object.keys(dirtyField).length ? { | ||
@@ -128,4 +122,4 @@ [fieldName]: dirtyField | ||
} | ||
return { ...acc, | ||
return { | ||
...acc, | ||
...(field.dirty ? { | ||
@@ -136,3 +130,2 @@ [fieldName]: field.value | ||
}; | ||
return Object.entries(fieldBag).reduce(reduceFn, {}); | ||
@@ -144,13 +137,9 @@ } | ||
} | ||
if (!arrA || !arrB) { | ||
return false; | ||
} | ||
const len = arrA.length; | ||
if (arrB.length !== len) { | ||
return false; | ||
} | ||
for (let i = 0; i < len; i++) { | ||
@@ -161,3 +150,2 @@ if (arrA[i] !== arrB[i]) { | ||
} | ||
return true; | ||
@@ -164,0 +152,0 @@ } |
@@ -40,13 +40,9 @@ 'use strict'; | ||
} | ||
const matches = matcher(input); | ||
if (matches) { | ||
return; | ||
} | ||
if (typeof errorContent === 'function') { | ||
return errorContent(input); | ||
} | ||
return errorContent; | ||
@@ -53,0 +49,0 @@ }; |
{ | ||
"name": "@shopify/react-form", | ||
"version": "0.0.0-snapshot-20240308174203", | ||
"version": "0.0.0-snapshot-20240620045713", | ||
"license": "MIT", | ||
@@ -24,6 +24,6 @@ "description": "Manage React forms tersely and safely-typed with no magic using React hooks", | ||
"engines": { | ||
"node": "^14.17.0 || >=16.0.0" | ||
"node": ">=18.12.0" | ||
}, | ||
"peerDependencies": { | ||
"react": ">=16.8.0 <19.0.0" | ||
"react": ">=18.0.0 <19.0.0" | ||
}, | ||
@@ -39,4 +39,4 @@ "files": [ | ||
"dependencies": { | ||
"@shopify/predicates": "^3.0.1", | ||
"@shopify/react-hooks": "0.0.0-snapshot-20240308174203", | ||
"@shopify/predicates": "^3.1.0", | ||
"@shopify/react-hooks": "0.0.0-snapshot-20240620045713", | ||
"fast-deep-equal": "^3.1.3", | ||
@@ -43,0 +43,0 @@ "get-value": "^3.0.1" |
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
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
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
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
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
238622
3618
+ Added@shopify/react-hooks@0.0.0-snapshot-20240620045713(transitive)
- Removed@shopify/react-hooks@0.0.0-snapshot-20240308174203(transitive)
Updated@shopify/predicates@^3.1.0