informed
Version:
A lightweight framework and utility for building powerful forms in React applications
1,174 lines (1,079 loc) • 38.9 kB
JavaScript
import { createClass as _createClass, typeof as _typeof, createForOfIteratorHelper as _createForOfIteratorHelper, toConsumableArray as _toConsumableArray, objectSpread2 as _objectSpread2, slicedToArray as _slicedToArray, classCallCheck as _classCallCheck } from './_virtual/_rollupPluginBabelHelpers.js';
import { ObjectMap } from './ObjectMap.js';
import { Debug } from './debug.js';
export { unwrap } from './proxy.js';
var debug = Debug('informed:utils' + '\t');
// https://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript
var uuidv4 = function uuidv4() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = Math.random() * 16 | 0,
v = c == 'x' ? r : r & 0x3 | 0x8;
return v.toString(16);
});
};
var getParentPath = function getParentPath(name) {
// Example friends >>>> friends
// Example father.name >>>> father
// Example friends[0] >>>> friends
// Example friends[0].father.name >>>> friends[0].father
// Example friends[0].father.siblings[1].name >>>> friends[0].father.siblings[1]
var parentArrayPath = name.replace(/(.*)[.[].*/, '$1');
return parentArrayPath;
};
function debounceByName(func) {
var _this = this;
var timeout = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 300;
var timers = {};
return function () {
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
var name = args[0];
clearTimeout(timers[name]);
// console.log('CLEARING', name);
timers[name] = setTimeout(function () {
// console.log('APPLYING', name);
func.apply(_this, args);
}, timeout);
};
}
function debounce(func) {
var _this2 = this;
var timeout = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 300;
var timer;
return function () {
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
args[_key2] = arguments[_key2];
}
clearTimeout(timer);
timer = setTimeout(function () {
func.apply(_this2, args);
}, timeout);
};
}
// Example debounce
// function saveInput(){
// console.log('Saving data');
// }
// const processChange = debounce(() => saveInput());
// Elon -----------
var Elon = /*#__PURE__*/function () {
function Elon() {
_classCallCheck(this, Elon);
}
_createClass(Elon, null, [{
key: "inspect",
value:
// Static functions
function inspect(validators) {
// Create validation funciton
return function (value, values) {
for (var i = 0; i < validators.length; i++) {
// get validator
var validator = validators[i];
// call validator
var res = validator(value, values);
// If we have error return it ( exit early )
if (res) return res;
}
};
}
}]);
return Elon;
}();
// Is Child
var isChild = function isChild(parent, child) {
// console.log(
// 'PARENT',
// parent,
// 'CHILD',
// child,
// 'RES',
// child.slice(0, parent.length) === parent
// );
// Example1
// parent = "friends[1]"
// child = "friends[1].foo"
// child.startsWith(`${parent}.`)
// "friends[1].foo".startsWith("friends[1]")
// ==> true
// Example2
// parent = "friends[1].foo.friends[1]"
// child = "friends[1].foo"
// child.startsWith(`${parent}.`)
// "friends[1].foo".startsWith("friends[1].foo.friends[1]")
// ==> false
return child.startsWith("".concat(parent, ".")) || child.startsWith("".concat(parent, "["));
};
var generateOnChange = function generateOnChange(_ref) {
var fieldType = _ref.fieldType,
setValue = _ref.setValue,
multiple = _ref.multiple,
ref = _ref.ref;
var setter = function setter(e) {
return setValue(e);
};
if (fieldType === 'text' || fieldType === 'textArea' || fieldType === 'number') {
setter = function setter(e) {
setValue(e.target.value, e);
};
}
if (fieldType === 'select') {
setter = function setter(e) {
var selected = Array.from(ref.current).filter(function (option) {
return option.selected;
}).map(function (option) {
return option.value;
});
setValue(multiple ? selected : selected[0] || '', e);
};
}
if (fieldType === 'checkbox') {
setter = function setter(e) {
setValue(e.target.checked, e);
};
}
return function (e) {
setter(e);
};
};
var generateOnBlur = function generateOnBlur(_ref2) {
var setTouched = _ref2.setTouched;
return function (e) {
setTouched(true, e);
};
};
var generateOnFocus = function generateOnFocus(_ref3) {
var setFocused = _ref3.setFocused;
return function (e) {
setFocused(true, e);
};
};
var generateValue = function generateValue(_ref4) {
var fieldType = _ref4.fieldType,
maskedValue = _ref4.maskedValue,
multiple = _ref4.multiple,
value = _ref4.value;
switch (fieldType) {
case 'text':
case 'number':
return !maskedValue && maskedValue !== 0 ? '' : maskedValue;
case 'textArea':
return !maskedValue ? '' : maskedValue;
case 'select':
return value || (multiple ? [] : '');
case 'checkbox':
return !!value;
default:
return value;
}
};
// https://stackoverflow.com/questions/52367849/remove-empty-null-values-from-nested-object-es6-clean-nested-objects
var sanitize = function sanitize(obj) {
if (!obj) return obj;
Object.keys(obj).forEach(function (key) {
return obj[key] && _typeof(obj[key]) === 'object' && sanitize(obj[key]) || obj[key] === undefined && delete obj[key];
});
return obj;
};
/* -------------------------- Error Utils ----------------------------- */
var yupToFormErrors = function yupToFormErrors(yupError) {
var errors = {};
if (yupError.inner) {
if (yupError.inner.length === 0) {
// console.log(yupError.path);
ObjectMap.set(errors, yupError.path, yupError.message);
return;
}
var _iterator = _createForOfIteratorHelper(yupError.inner),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var err = _step.value;
if (!ObjectMap.get(errors, err.path)) {
// console.log(errors, err.path, err.message);
ObjectMap.set(errors, err.path, err.message);
}
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
}
return errors;
};
var validateYupSchema = function validateYupSchema(schema, values) {
try {
schema.validateSync(values, {
abortEarly: false
});
} catch (e) {
var formErrors = yupToFormErrors(e);
return formErrors;
}
};
var yupToFormError = function yupToFormError(yupError) {
if (yupError.inner) {
if (yupError.inner.length === 0) {
return;
}
var err = yupError.inner[0];
return err.message;
}
};
var validateYupField = function validateYupField(schema, value) {
try {
schema.validateSync(value, {
abortEarly: false
});
} catch (e) {
return yupToFormError(e);
}
};
var validateAjvSchema = function validateAjvSchema(validate, data) {
validate(data);
var errors = {};
if (validate.errors) {
validate.errors.forEach(function (_ref5) {
var message = _ref5.message,
dataPath = _ref5.dataPath,
keyword = _ref5.keyword,
params = _ref5.params;
var path = dataPath;
// Special case for required
if (keyword === 'required') {
path = "".concat(path, ".").concat(params.missingProperty);
}
// Get rid of leading dot
path = path.replace('.', '');
// console.log('PATH', path, message);
// TODO get message from informed if present
ObjectMap.set(errors, path, message);
});
}
return errors;
};
var validateRequired = function validateRequired(value, required, getErrorMessage, noFalsy) {
// Normal required validation
if (required && (value == null || value === '' || Array.isArray(value) && value.length == 0)) {
return typeof required === 'string' ? required : getErrorMessage('required') || 'This field is required';
}
// No falsey validation
if (noFalsy && !value) {
return typeof noFalsy === 'string' ? noFalsy : getErrorMessage('noFalsy') || 'This field is required';
}
};
var validateMax = function validateMax(value, max, getErrorMessage) {
if (max != null && value > max) {
return getErrorMessage('maximum') || "This field should NOT be more than ".concat(max);
}
return undefined;
};
var validateMin = function validateMin(value, min, getErrorMessage) {
if (min != null && value < min) {
return getErrorMessage('minimum') || "This field should NOT be less than ".concat(min);
}
return undefined;
};
var validateMaxLength = function validateMaxLength(value, maxLength, getErrorMessage) {
if (maxLength != null && (value === null || value === void 0 ? void 0 : value.length) > maxLength) {
return getErrorMessage('maxLength') || "This field should NOT be more than ".concat(maxLength, " characters");
}
return undefined;
};
var validateMinLength = function validateMinLength(value, minLength, getErrorMessage) {
if (minLength != null && (value === null || value === void 0 ? void 0 : value.length) < minLength) {
return getErrorMessage('minLength') || "This field should NOT be shorter than ".concat(minLength, " characters");
}
return undefined;
};
var validatePattern = function validatePattern(value, pattern, getErrorMessage) {
if (pattern != null && !new RegExp(pattern).test(value) && value) {
return getErrorMessage('pattern') || "This field should match pattern \"".concat(pattern, "\";");
}
return undefined;
};
var generateValidationFunction = function generateValidationFunction(validationFuncRef, yupSchema, _ref6) {
var required = _ref6.required,
noFalsy = _ref6.noFalsy,
minimum = _ref6.minimum,
maximum = _ref6.maximum,
minLength = _ref6.minLength,
maxLength = _ref6.maxLength,
pattern = _ref6.pattern,
getErrorMessage = _ref6.getErrorMessage,
validateModified = _ref6.validateModified,
fieldApi = _ref6.fieldApi,
formController = _ref6.formController,
scope = _ref6.scope,
name = _ref6.name;
return function (val, values) {
var error;
if (validateModified && fieldApi.getModified() === undefined) {
return;
}
if (required || noFalsy) {
error = validateRequired(val, required, getErrorMessage, noFalsy);
if (error !== undefined) return error;
}
if (minimum != null) {
error = validateMin(val, minimum, getErrorMessage);
if (error !== undefined) return error;
}
if (maximum != null) {
error = validateMax(val, maximum, getErrorMessage);
if (error !== undefined) return error;
}
if (minLength != null) {
error = validateMinLength(val, minLength, getErrorMessage);
if (error !== undefined) return error;
}
if (maxLength != null) {
error = validateMaxLength(val, maxLength, getErrorMessage);
if (error !== undefined) return error;
}
if (pattern) {
error = validatePattern(val, pattern, getErrorMessage);
if (error !== undefined) return error;
}
if (yupSchema) {
error = validateYupField(yupSchema, val);
if (error !== undefined) return error;
}
if (validationFuncRef.current) {
error = validationFuncRef.current(val, values, {
formState: formController.getFormState(),
formApi: formController.getFormApi(),
scope: scope,
name: name
});
if (error !== undefined) return error;
}
return error;
};
};
/** --------------------------------------------------------------------------------------------
* Helper function for getFormatter
* @param {*} formatter
* @returns
*/
var formatterFromString = function formatterFromString(formatter) {
return formatter.split('').map(function (_char) {
if (_char === '#') {
return /\d/;
}
if (_char === '*') {
return /[\w]/;
}
return _char;
});
};
/* -------------------------- Formatter ----------------------------- */
var getFormatter = function getFormatter(formatter, value, full) {
// If mask is a string turn it into an array;
if (typeof formatter === 'string') {
return formatterFromString(formatter);
}
// If mask is a function use it to genreate current mask
if (typeof formatter === 'function') {
var frmtr = formatter(value, full);
if (typeof frmtr === 'string') {
return formatterFromString(frmtr);
}
return frmtr;
}
if (Array.isArray(formatter)) {
return formatter;
}
// Should never make it here throw
throw new Error('Formatter must be string, array, or function');
};
var matchingIndex = function matchingIndex(a, b) {
var i = 0;
var mi = -1;
var matching = true;
// a = "+1 "
// b = "+12"
while (matching && i < a.length) {
if (a[i] == b[i]) {
mi = i;
} else {
matching = false;
}
i = i + 1;
}
return mi;
};
var informedParse = function informedParse(val, parser) {
// Our parser is an object! so we must parse for each key
// Example:
//
// formatter: {
// a: formatter,
// b: formatter
// }
if (_typeof(parser) === 'object' && !Array.isArray(parser)) {
var parsedVal = {};
Object.keys(val).forEach(function (key) {
// parser['foo'] = val['foo']
// Only try to parse if we have parser for this key!!!
if (parser[key]) {
var value = parser[key](val[key]);
parsedVal[key] = value;
} else {
parsedVal[key] = val[key];
}
});
return parsedVal;
}
// Simply pass along if its a flat formatter
return parser(val);
};
var informedFormat = function informedFormat(val, frmtr, old) {
var dir = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'ltr';
// Our formatter is an object! so we must format for each key
// Example:
//
// formatter: {
// a: formatter,
// b: formatter
// }
if (_typeof(frmtr) === 'object' && !Array.isArray(frmtr)) {
var formattedVal = {};
var formattedOffset = {};
Object.keys(val).forEach(function (key) {
// Only try to format if we have formatter for this key!!!
if (frmtr[key]) {
// console.log('Old', old);
var _informedFormatter = informedFormatter(val[key], frmtr[key], old ? old[val] : undefined, val, dir),
value = _informedFormatter.value,
offset = _informedFormatter.offset;
formattedVal[key] = value;
formattedOffset[key] = offset;
} else {
formattedVal[key] = val[key];
formattedOffset[key] = 0;
}
});
return {
value: formattedVal,
offset: formattedOffset
};
}
// Simply pass along if its a flat formatter
return informedFormatter(val, frmtr, old, val, dir);
};
var informedFormatter = function informedFormatter(val, frmtr, old, full, dir) {
// console.log('Formatting', val);
debug('Formatting', val);
debug('Full Value', full);
// Null check
if (val == null) {
return {
value: val,
offset: 0
};
}
var value = "".concat(val);
// Generate formatter array
var formatter = getFormatter(frmtr, value, full);
// Start to fill in the array
// Example: phone formatter
// formatter =['+', '1', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/]
// value examples:
// "1231231234 ----> +1 123-123-1234
// "+" ----> +
// "+1" ----> +1
// "+2" ----> +1 2
// "1" ----> +1 1
// "1234" ----> +1 123-4
// "123a" ----> +1 123
// ADD LOGS FOR TETING ---------------------------
// console.log('New', value);
// console.log('Old', old);
// console.log('Formatter', formatter);
// Determine prefix length and suffix start
var prefixLength = formatter.findIndex(function (v) {
return typeof v != 'string';
});
// If we have a suffix
var suffixStart = null;
if (typeof formatter[formatter.length - 1] === 'string') {
suffixStart = formatter.length - _toConsumableArray(formatter).reverse().findIndex(function (v) {
return typeof v != 'string';
});
}
// Formatted value
var formatted = [];
// The characters from the current value
var chars = value.split('');
// To track the value index during itteration
var vIndex = 0;
var start = 0;
// If the value matches part of the prefix take it out
// Example prefix = "+1 " value = ["+1 123-123-1234", "+12", "+2"]
var matchIndex = matchingIndex(formatter.slice(0, prefixLength), chars.slice(0, prefixLength));
// console.log('Matching index', matchIndex);
if (matchIndex > -1) {
//vIndex = prefixLength;
vIndex = matchIndex + 1;
formatted = formatted.concat(formatter.slice(0, matchIndex + 1));
start = matchIndex + 1;
}
// Example prefix = "+1 " value=["1", "1234"]
if (matchIndex < 0) {
// Start past the prefix
formatted = formatted.concat(formatter.slice(0, prefixLength));
start = prefixLength;
}
// Fill in the stuff
for (var i = start; i < formatter.length; i++) {
// Get current formatter location matcher
var matcher = formatter[i];
// Chec to see if there is more value to look at
if (vIndex != chars.length) {
// Get the current value character
var curChar = chars[vIndex];
// Special case for function
if (typeof matcher === 'function') {
formatted.push(matcher(curChar));
vIndex = vIndex + 1;
} else {
// If type is string normal compare otherwise regex compare
// console.log('MATCHER', matcher);
var match = typeof matcher === 'string' ? matcher === curChar : matcher.test(curChar);
// If the current character of the value matches and matcher is a string
// "1" === "1"
if (match && typeof matcher === 'string') {
formatted.push(matcher);
//if( pastPrefix ){
vIndex = vIndex + 1;
//}
}
// If the current character does not match and matcher is a stirng
// "1" != "+"
else if (!match && typeof matcher === 'string') {
// Special check for 123a ---> dont want "+1 123-"
// Special check for 1234 ---> DO want "+1 123-4"
if (vIndex != chars.length) formatted.push(matcher);
}
// If the current character matches and the matcher is not a string
// /\d/.test("2")
else if (match && typeof matcher != 'string') {
formatted.push(curChar);
vIndex = vIndex + 1;
}
// If the current character does NOT match and the matecer is regex
// /\d/.test("a")
else if (!match && typeof matcher != 'string') {
// Throw out this value
vIndex = vIndex + 1;
i = i - 1;
}
}
} else {
// console.log('WTF i', i, 'suffixStart', suffixStart);
// If mattcher is a string and we are at suffix keep going
if (typeof matcher === 'string' && suffixStart && i >= suffixStart) {
formatted.push(matcher);
} else {
// Otherwise we want to break out
break;
}
}
}
// ADD LOGS FOR TETING ---------------------------
// console.log('FORMATTEDARR', formatted);
// console.log('VALUE', value, value.length);
var formattedString = formatted.join('');
// console.log('FORMATTED', formattedString, formattedString.length);
// For the following cases the "|" represents the cursor position
//
// Case1:
// oldValue = "+1 12|" ( length 5 )
// value = "+1 123|" ( length 6)
// formattedString = "+1 123-" ( length 7 )
// offset = 1 ( we need to move cursur over by 1 )
//
// Case2:
// oldValue = "1,234|.25" ( length 8 )
// value = "1,23|.25" ( length 7 )
// formattedString = "123.25" ( length 6 )
// offset = 1 ( we need to move cursur over by -1 because a format character got removed )
var offset = value ? formattedString.length - value.length : 0;
// ADD LOGS FOR TETING ---------------------------
// console.log('OFFSET', offset);
// Special case1:
// Suffix is '%'
// user typed backspace
// 20%|
// 20|%
// ^
// suffixStart (2)
//
// New: 20
// Old: 20%
//
// New length is less than old length
// And length of new is greater than or equal two suffix start
var case1 = suffixStart && value && old && value.length < old.length && value.length >= suffixStart && dir != 'rtl';
// Special case2:
// Suffix is '%'
// user types 20|
// we want cursor to be here
// 20|%
// Note: we DONT want to do this if we also added a new character
// Example: 7000| BND --- user types zero "0" --> 70 000| BND
// to solve we can just check to see if the suffix was already there :)
var suffix = formatter.slice(suffixStart).join('');
// console.log('SUFFIX', suffix);
var case2 = suffixStart && formatted.length > suffixStart && (!old || typeof old === 'string' && !old.includes(suffix));
// && dir != 'rtl';
if (case1 || case2) {
offset = 0;
// console.log('OFFSET OVERRIDE', offset, case1 ? 'case1' : 'case2');
// Special case if right to left then we actually want to offset by one
if (dir == 'rtl') offset = 1;
// Special case, we want to diable keeping suffix on backspace in react native
if (typeof navigator !== 'undefined' && navigator.product === 'ReactNative' && value && old && value.length < old.length) {
// I'm in react-native
formattedString = formattedString.slice(0, suffixStart);
}
}
// ADD LOGS FOR TETING ---------------------------
// console.log('OFFSET', offset);
return {
value: formattedString,
offset: offset
};
};
/* --------------------------------------- createIntlNumberFormatter --------------------------------------- */
var createIntlNumberFormatter = function createIntlNumberFormatter(locale) {
var _toParts$find$value, _toParts$find, _toParts$find2;
var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var _ref7 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {},
formatToParts = _ref7.formatToParts;
var numberFormatter = new Intl.NumberFormat(locale, opts);
// TODO at some point this was used to find the decimal char.. not sure why I stopped using it but kept in case i see future issue.
// const numberFormatterWithoutOpts = new Intl.NumberFormat(locale, opts);
var toParts = function toParts(v) {
return numberFormatter.formatToParts(v);
};
// If user passed in custom function use that instead
if (formatToParts) {
toParts = function toParts(v) {
return formatToParts(v, locale, opts);
};
}
var decimalChar = (_toParts$find$value = (_toParts$find = toParts(0.1).find(function (_ref8) {
var type = _ref8.type;
return type === 'decimal';
})) === null || _toParts$find === void 0 ? void 0 : _toParts$find.value) !== null && _toParts$find$value !== void 0 ? _toParts$find$value : '.';
// console.log('-1 number parts', numberFormatter.formatToParts(-1));
// Try to find minus sign
var minusChar = (_toParts$find2 = toParts(-1).find(function (_ref9) {
var type = _ref9.type;
return type === 'minusSign';
})) === null || _toParts$find2 === void 0 ? void 0 : _toParts$find2.value;
// special case if we did not find it then look one more time but for a literal ( accounting will lead to this case where "(" is neg symbol )
if (!minusChar) {
var _toParts$find$value2, _toParts$find3;
minusChar = (_toParts$find$value2 = (_toParts$find3 = toParts(-1).find(function (_ref10) {
var type = _ref10.type;
return type === 'literal';
})) === null || _toParts$find3 === void 0 ? void 0 : _toParts$find3.value) !== null && _toParts$find$value2 !== void 0 ? _toParts$find$value2 : '-';
}
// function isRegexEqual(x, y) {
// return (
// x instanceof RegExp &&
// y instanceof RegExp &&
// x.source === y.source &&
// x.global === y.global &&
// x.ignoreCase === y.ignoreCase &&
// x.multiline === y.multiline
// );
// }
// function findLastIndex(arr, predicate) {
// let l = arr.length;
// // eslint-disable-next-line no-plusplus
// while (l--) {
// if (predicate(arr[l])) return l;
// }
// return -1;
// }
// function insert(arr, index, value) {
// const nextArr = [...arr];
// if (Array.isArray(value)) {
// nextArr.splice(index, 0, ...value);
// } else {
// nextArr.splice(index, 0, value);
// }
// return nextArr;
// }
function stripNonNumeric(str) {
return "".concat(str).replace(/\D/g, '');
}
function toNumberString(str) {
var decimalChar = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '.';
// Special case if user types the decimal char
if (str === decimalChar) {
return '';
}
// If its a number we always use dot notation
if (typeof str === 'number') {
return "".concat(str).split('.').map(function (splitStr) {
return stripNonNumeric(splitStr);
}).join('.');
}
// Create a regex to replace all but the first occurrence of the decimalChar.
// let regex = new RegExp(`(.*?\\${decimalChar}.*?)\\${decimalChar}(.*)`, 'g');
return "".concat(str) // .replace(regex, '$1$2')
.split(decimalChar).map(function (splitStr) {
return stripNonNumeric(splitStr);
}).join('.');
}
function toFloat(str) {
var decimalChar = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '.';
if (typeof str === 'number') {
return str;
}
var _float = parseFloat(toNumberString(str, decimalChar));
// console.log('ISNAN', Number.isNaN(float));
return !Number.isNaN(_float) ? _float : undefined;
}
function mask(value, ogValue) {
// console.log('--------------\n');
// value = -3000.25
// console.log('decChar', decimalChar);
// console.log('minusChar', minusChar);
// console.log('VAL', value);
var isNegative = "".concat(value).includes(minusChar) || "".concat(value).includes('-');
// In case the value is a number from initial value we want to pass the OG value ( not the one we turned into a string in informedFormatter )
var _float2 = toNumberString(ogValue, decimalChar);
// float = 3000.25
// console.log('float', float);
// Special case if only decimal Char
var isDecimalChar = false;
if (_float2 == '.') {
isDecimalChar = true;
}
var fraction = "".concat(_float2).split('.')[1];
// fraction = 25
// console.log('fraction', fraction);
var number = isNegative ? -Number(_float2) : Number(_float2);
// console.log('number', number);
var numberParts = toParts(number);
// Special case, if number parts does not contain a "decimal" than we want to throw out the decimal from the value
// const hasDecimal = numberParts.find(part => part.type === 'decimal');
// number-parts =
// 0: {type: 'minusSign', value: '-'}
// 1: {type: 'currency', value: '$'}
// 2: {type: 'integer', value: '3'}
// 3: {type: 'group', value: ','}
// 4: {type: 'integer', value: '000'}
// 5: {type: 'decimal', value: '.'}
// 6: {type: 'fraction', value: '25'}
// console.log('number-parts', numberParts);
// const hasFraction = numberParts.find(p => p.type === 'fraction');
// In the case user types "1." or "1.0" we need to add the fraction part
// This only occurs if we dont have minimumFractionDigits to force the fraction
// if (fraction != null && !hasFraction) {
// numberParts.push(
// { type: 'decimal', value: decimalChar },
// { type: 'fraction', value: fraction }
// );
// }
// console.log('number-parts after fraction check', numberParts);
var maskArray = numberParts.reduce(function (pv, _ref11) {
var type = _ref11.type,
partValue = _ref11.value;
// PV [] minusSign -
// PV ['-'] currency $
// PV ['-', '$'] integer 3
// PV ['-', '$', /\d/] group ,
// PV ['-', '$', /\d/, ','] integer 000
// PV ['-', '$', /\d/, ',', /\d/, /\d/, /\d/] decimal .
// PV ['-', '$', /\d/, ',', /\d/, /\d/, /\d/, '.'] fraction 25
// console.log('PV', pv, type, partValue);
if (['decimal', 'fraction'].includes(type) && fraction == null) {
return pv;
}
// // Special case where we have no fraction but need to pad
// if (['fraction'].includes(type) && fraction == null) {
// return [...pv, ...partValue.split('')];
// }
if (['integer', 'fraction'].includes(type)) {
return [].concat(_toConsumableArray(pv), _toConsumableArray(partValue.split('').filter(function (_, index) {
return type === 'fraction' ? index < fraction.length : true;
}).map(function () {
return /\d/;
})));
}
if (type === 'currency' || type === 'minusSign') {
return [].concat(_toConsumableArray(pv), _toConsumableArray(partValue.split('')));
}
return [].concat(_toConsumableArray(pv), [partValue]);
}, []);
// console.log('PV', maskArray);
// let lastDigitIndex = findLastIndex(maskArray, maskChar => {
// return isRegexEqual(maskChar, /\d/);
// });
// console.log('lastDigitIndex', lastDigitIndex);
// if (
// maskArray.indexOf(decimalChar) === -1 &&
// `${value}`.indexOf(decimalChar) !== -1 &&
// hasDecimal
// ) {
// maskArray = insert(maskArray, lastDigitIndex + 1, [decimalChar]);
// lastDigitIndex += 2; // we want to insert a new number after the decimal
// }
// const endOfMask = maskArray.slice(lastDigitIndex + 1).join('');
// maskArray = [...maskArray.slice(0, lastDigitIndex + 1), endOfMask];
if (isDecimalChar) {
maskArray = maskArray.map(function (item) {
return item == 'NaN' ? "0".concat(decimalChar) : item;
});
}
// console.log('maskArray', maskArray);
return maskArray;
}
var parser = function parser(value) {
if (value == null) {
return undefined;
}
var isNegative = "".concat(value).includes(minusChar);
// console.log('TOPARSE', value);
return isNegative ? -toFloat(value, decimalChar) : toFloat(value, decimalChar);
};
return {
formatter: mask,
parser: parser
};
};
/* --------------------------------------- Schema Shit --------------------------------------- */
// Examples
// field = "name" ---> properties.name
// field = "brother.name" ---> properties.brother.properties.name
// field = "brother.siblings[1].friend.name" ---> properties.brother.properties.siblings.items.properties.friend.properties.name
var getSchemaPathFromJsonPath = function getSchemaPathFromJsonPath(jsonPath) {
// Convert
var schemaPath = jsonPath.replace(/\./g, '.properties.').replace(/\[\d+\]/g, '.items');
// Add first properties
schemaPath = "properties.".concat(schemaPath);
return schemaPath;
};
var computeFieldFromProperty = function computeFieldFromProperty(propertyName, property, prefix) {
var uiControl = property['ui:control'],
inputProps = property['ui:props'],
uiBefore = property['ui:before'],
uiAfter = property['ui:after'],
oneOf = property.oneOf,
items = property.items,
schemaEnum = property["enum"],
label = property.title,
minimum = property.minimum,
maximum = property.maximum,
minLength = property.minLength,
maxLength = property.maxLength,
pattern = property.pattern,
required = property.required,
type = property.type,
subProperties = property.properties,
allOf = property.allOf,
propertyOrder = property.propertyOrder,
errorMessage = property.errorMessage;
// Set Id if not passed
var id = uuidv4();
if (inputProps && inputProps.id) {
id = inputProps.id;
}
var field = {
// componentType: uiControl ?? (oneOf && 'select') ?? type,
componentType: uiControl !== null && uiControl !== void 0 ? uiControl : type,
name: prefix ? "".concat(prefix, ".").concat(propertyName) : propertyName,
type: type,
uiBefore: uiBefore,
uiAfter: uiAfter,
properties: type === 'object' ? subProperties : undefined,
allOf: type === 'object' ? allOf : undefined,
propertyOrder: type === 'object' ? propertyOrder : undefined,
items: type === 'array' ? items : undefined,
propertyName: propertyName,
required: required,
props: _objectSpread2({
label: label,
id: id,
minimum: minimum,
maximum: maximum,
minLength: minLength,
maxLength: maxLength,
pattern: pattern,
errorMessage: errorMessage,
required: required
}, inputProps)
};
// console.log('NAME', propertyName, inputProps);
if (oneOf) {
var options = property.oneOf.map(function (option) {
var _option$uiProps = option['ui:props'],
inputProps = _option$uiProps === void 0 ? {} : _option$uiProps;
return _objectSpread2({
value: option["const"],
label: option.title
}, inputProps);
});
field.props.options = options;
}
if (schemaEnum) {
var _options = property["enum"].map(function (val) {
return {
value: val,
label: val
};
});
field.props.options = _options;
}
if (items && items.oneOf) {
var _options2 = items.oneOf.map(function (option) {
var _option$uiProps2 = option['ui:props'],
inputProps = _option$uiProps2 === void 0 ? {} : _option$uiProps2;
return _objectSpread2({
value: option["const"],
label: option.title
}, inputProps);
});
field.props.options = _options2;
}
return field;
};
var computeFieldsFromSchema = function computeFieldsFromSchema(schema, onlyValidateSchema) {
if (!schema || onlyValidateSchema) {
return {
properties: [],
conditions: [],
components: []
};
}
// Grab properties and items off of schema
var _schema$properties = schema.properties,
properties = _schema$properties === void 0 ? {} : _schema$properties,
allOf = schema.allOf,
_schema$propertyOrder = schema.propertyOrder,
propertyOrder = _schema$propertyOrder === void 0 ? [] : _schema$propertyOrder;
if (Object.keys(properties).length > 0) {
// Attempt to generate fields from properties
var fields = Object.keys(properties).sort(function (a, b) {
var aIndex = propertyOrder.indexOf(a);
var bIndex = propertyOrder.indexOf(b);
return (aIndex > -1 ? aIndex : propertyOrder.length + 1) - (bIndex > -1 ? bIndex : propertyOrder.length + 1);
}).map(function (propertyName) {
return propertyName;
});
var conditions = [];
var components = [];
// Check for all of ( we have conditionals )
if (allOf) {
allOf.forEach(function (item) {
if (item["if"]) {
// Determine if the "then" properties are new or already in fields
var newItem = _objectSpread2({}, item);
newItem.then = _objectSpread2(_objectSpread2({}, item.then), {}, {
properties: {}
});
newItem.thenProps = {};
Object.keys(item.then.properties).forEach(function (name) {
if (!fields.includes(name)) {
// This is a completley new field!
newItem.then.properties[name] = item.then.properties[name];
} else {
// This field has been spotted above, and therefore is just new properties based on conditional
newItem.thenProps[name] = item.then.properties[name];
}
});
conditions.push(newItem);
} else {
components.push(item);
}
});
}
return {
properties: fields,
conditions: conditions,
components: components
};
}
return {
properties: [],
conditions: [],
components: []
};
};
function checkCondition(condition, propertyValue) {
// if (!isPlainObject(condition)) {
// return false;
// }
return Object.entries(condition).every(function (_ref12) {
var _ref13 = _slicedToArray(_ref12, 2),
keyword = _ref13[0],
value = _ref13[1];
// console.log('KEYWORD', keyword, value, propertyValue);
switch (keyword) {
case 'const':
if (Array.isArray(propertyValue) && value) {
return propertyValue.sort().toString() == value.sort().toString();
} else {
return propertyValue === value;
}
case 'minimum':
return propertyValue >= value;
case 'exclusiveMinimum':
return propertyValue > value;
case 'maximum':
return propertyValue <= value;
case 'exclusiveMaximum':
return propertyValue < value;
case 'enum':
if (Array.isArray(value) && !Array.isArray(propertyValue)) {
return value.includes(propertyValue);
}
if (Array.isArray(value) && Array.isArray(propertyValue)) {
return propertyValue.every(function (a) {
return value.includes(a);
});
}
return false;
case 'oneOf':
if (Array.isArray(value) && !Array.isArray(propertyValue)) {
return value.includes(propertyValue);
}
if (Array.isArray(value) && Array.isArray(propertyValue)) {
return value.find(function (a) {
return propertyValue.includes(a);
});
}
return false;
case 'pattern':
return new RegExp(value).test(propertyValue);
// case 'properties':
// // eslint-disable-next-line no-use-before-define
// return checkProperties(value, values, propertyPath);
case 'not':
if (_typeof(value) === 'object' && value["enum"]) {
if (Array.isArray(value["enum"]) && !Array.isArray(propertyValue)) {
return !value["enum"].includes(propertyValue);
}
if (Array.isArray(value["enum"]) && Array.isArray(propertyValue)) {
return !propertyValue.every(function (a) {
return value["enum"].includes(a);
});
}
}
return propertyValue !== value;
default:
// not supported keywords return false
return false;
}
});
}
export { Elon, checkCondition, computeFieldFromProperty, computeFieldsFromSchema, createIntlNumberFormatter, debounce, debounceByName, generateOnBlur, generateOnChange, generateOnFocus, generateValidationFunction, generateValue, getParentPath, getSchemaPathFromJsonPath, informedFormat, informedFormatter, informedParse, isChild, sanitize, uuidv4, validateAjvSchema, validateMax, validateMaxLength, validateMin, validateMinLength, validateRequired, validateYupField, validateYupSchema, yupToFormError, yupToFormErrors };