@bhch/react-json-form
Version:
Create forms using JSON Schema
1,403 lines (1,208 loc) • 157 kB
JavaScript
var React$1 = require('react');
var ReactModal = require('react-modal');
var ReactDOM = require('react-dom');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var React__default = /*#__PURE__*/_interopDefaultLegacy(React$1);
var ReactModal__default = /*#__PURE__*/_interopDefaultLegacy(ReactModal);
var ReactDOM__default = /*#__PURE__*/_interopDefaultLegacy(ReactDOM);
function _extends() {
_extends = Object.assign ? Object.assign.bind() : function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
return _extends.apply(this, arguments);
}
function _objectWithoutPropertiesLoose(source, excluded) {
if (source == null) return {};
var target = {};
var sourceKeys = Object.keys(source);
var key, i;
for (i = 0; i < sourceKeys.length; i++) {
key = sourceKeys[i];
if (excluded.indexOf(key) >= 0) continue;
target[key] = source[key];
}
return target;
}
/* Symbol for joining coordinates.
* Earlier, a hyphen (-) was used. But that caused problems when
* object keys had hyphen in them. So, we're switching to a less
* commonly used symbol.
*/
const JOIN_SYMBOL = '§';
/* HTML field name prefix */
const FIELD_NAME_PREFIX = 'rjf';
/* Filler item for arrays to make them at least minItems long */
const FILLER = '__RJF_FILLER__';
const EditorContext = /*#__PURE__*/React__default["default"].createContext();
function capitalize$1(string) {
if (!string) return '';
return string.charAt(0).toUpperCase() + string.substr(1).toLowerCase();
}
function convertType(value, to) {
if (typeof value === to) return value;
if (to === 'number' || to === 'integer') {
if (typeof value === 'string') {
value = value.trim();
if (value === '') value = null;else if (!isNaN(Number(value))) value = Number(value);
} else if (typeof value === 'boolean') {
value = value === true ? 1 : 0;
}
} else if (to === 'boolean') {
if (value === 'false' || value === false) value = false;else value = true;
}
return value;
}
function actualType(value) {
/* Returns the "actual" type of the given value.
- array -> 'array'
- null -> 'null'
*/
let type = typeof value;
if (type === 'object') {
if (Array.isArray(value)) type = 'array';else if (value === null) type = 'null';
}
return type;
}
function getSchemaType(schema) {
/* Returns type of the given schema.
If schema.type is not present, it tries to guess the type.
If data is given, it will try to use that to guess the type.
*/
let type;
if (schema.hasOwnProperty('const')) type = actualType(schema.const);else type = normalizeKeyword(schema.type);
if (!type) {
if (schema.hasOwnProperty('properties') || schema.hasOwnProperty('keys')) type = 'object';else if (schema.hasOwnProperty('items')) type = 'array';else if (schema.hasOwnProperty('allOf')) type = 'allOf';else if (schema.hasOwnProperty('oneOf')) type = 'oneOf';else if (schema.hasOwnProperty('anyOf')) type = 'anyOf';else type = 'string';
}
return type;
}
function getVerboseName(name) {
if (name === undefined || name === null) return '';
name = name.replace(/_/g, ' ');
return capitalize$1(name);
}
function getCsrfCookie() {
let csrfCookies = document.cookie.split(';').filter(item => item.trim().indexOf('csrftoken=') === 0);
if (csrfCookies.length) {
return csrfCookies[0].split('=')[1];
} else {
// if no cookie found, get the value from the csrf form input
let input = document.querySelector('input[name="csrfmiddlewaretoken"]');
if (input) return input.value;
}
return null;
}
function joinCoords() {
/* Generates coordinates from given arguments */
return Array.from(arguments).join(JOIN_SYMBOL);
}
function splitCoords(coords) {
/* Generates coordinates */
return coords.split(JOIN_SYMBOL);
}
function getCoordsFromName(name) {
/* Returns coordinates of a field in the data from
* the given name of the input.
* Field names have FIELD_NAME_PREFIX prepended but the coordinates don't.
* e.g.:
* name: rjf-0-field (where rjf- is the FIELD_NAME_PREFIX)
* coords: 0-field
*/
return name.slice((FIELD_NAME_PREFIX + JOIN_SYMBOL).length);
}
function debounce(func, wait) {
let timeout;
return function () {
clearTimeout(timeout);
let args = arguments;
let context = this;
timeout = setTimeout(function () {
func.apply(context, args);
}, wait || 1);
};
}
function normalizeKeyword(kw) {
/* Converts custom supported keywords to standard JSON schema keywords */
if (Array.isArray(kw)) kw = kw.find(k => k !== 'null') || 'null';
switch (kw) {
case 'list':
return 'array';
case 'dict':
return 'object';
case 'keys':
return 'properties';
case 'choices':
return 'enum';
case 'datetime':
return 'date-time';
default:
return kw;
}
}
function getKeyword(obj, keyword, alias, default_value) {
/* Function useful for getting value from schema if a
* keyword has an alias.
*/
return getKey(obj, keyword, getKey(obj, alias, default_value));
}
function getKey(obj, key, default_value) {
/* Approximation of Python's dict.get() function. */
let val = obj[key];
return typeof val !== 'undefined' ? val : default_value;
}
function choicesValueTitleMap(choices) {
/* Returns a mapping of {value: title} for the given choices.
* E.g.:
* Input: [{'title': 'One', 'value': 1}, 2]
* Output: {1: 'One', 2: 2}
*/
let map = {};
for (let i = 0; i < choices.length; i++) {
let choice = choices[i];
let value, title;
if (actualType(choice) === 'object') {
value = choice.value;
title = choice.title;
} else {
value = choice;
title = choice;
}
map[value] = title;
}
return map;
}
function valueInChoices(schema, value) {
/* Checks whether the given value is in schema choices or not.
If schema doesn't have choices, returns true.
*/
let choices = getKeyword(schema, 'choices', 'enum');
if (!choices) return true;
let found = choices.find(choice => {
if (typeof choice == 'object') choice = choice.value;
return value == choice;
});
return found !== undefined ? true : false;
}
/* Set operations */
function isEqualset(a, b) {
return a.size === b.size && Array.from(a).every(i => b.has(i));
}
function isSubset(set, superset) {
for (const elem of set) {
if (!superset.has(elem)) {
return false;
}
}
return true;
}
function getBlankObject(schema, getRef) {
let keys = {};
let schema_keys = getKeyword(schema, 'keys', 'properties', {});
for (let key in schema_keys) {
let value = schema_keys[key];
let isRef = value.hasOwnProperty('$ref');
let isConst = value.hasOwnProperty('const');
if (isRef) {
value = _extends({}, getRef(value['$ref']), value);
delete value['$ref'];
}
let type = normalizeKeyword(value.type);
if (!type) {
// check for oneOf/anyOf
if (value.hasOwnProperty('oneOf')) value = value.oneOf[0];else if (value.hasOwnProperty('anyOf')) value = value.anyOf[0];
type = normalizeKeyword(value.type);
}
let default_ = value.default;
if (isConst) {
type = actualType(value.const);
default_ = value.const;
}
if (type === 'array') keys[key] = isRef ? [] : getBlankArray(value, getRef);else if (type === 'object') keys[key] = getBlankObject(value, getRef);else if (type === 'boolean') keys[key] = default_ === false ? false : default_ || null;else if (type === 'integer' || type === 'number') keys[key] = default_ === 0 ? 0 : default_ || null;else keys[key] = default_ || '';
}
if (schema.hasOwnProperty('oneOf')) keys = _extends({}, keys, getBlankObject(schema.oneOf[0]));
if (schema.hasOwnProperty('anyOf')) keys = _extends({}, keys, getBlankObject(schema.anyOf[0]));
if (schema.hasOwnProperty('allOf')) {
for (let i = 0; i < schema.allOf.length; i++) {
keys = _extends({}, keys, getBlankObject(schema.allOf[i]));
}
}
return keys;
}
function getBlankArray(schema, getRef) {
let minItems = getKeyword(schema, 'minItems', 'min_items') || 0;
if (schema.default && schema.default.length >= minItems) return schema.default;
let items = [];
if (schema.default) items = [...schema.default];
if (minItems === 0) return items;
if (schema.items.hasOwnProperty('$ref')) {
// :TODO: this mutates the original schema
// but i'll fix it later
schema.items = _extends({}, getRef(schema.items['$ref']), schema.items);
delete schema.items['$ref'];
}
let type = normalizeKeyword(schema.items.type);
if (!type) {
if (Array.isArray(schema.items['oneOf'])) type = getSchemaType(schema.items.oneOf[0]);else if (Array.isArray(schema.items['anyOf'])) type = getSchemaType(schema.items.anyOf[0]);else if (Array.isArray(schema.items['allOf'])) type = getSchemaType(schema.items.allOf[0]);else if (schema.items.hasOwnProperty('const')) type = actualType(schema.items.const);
}
if (type === 'array') {
while (items.length < minItems) items.push(getBlankArray(schema.items, getRef));
return items;
} else if (type === 'object') {
while (items.length < minItems) items.push(getBlankObject(schema.items, getRef));
return items;
} else if (type === 'oneOf') {
while (items.length < minItems) items.push(getBlankOneOf(schema.items, getRef));
return items;
} else if (type === 'anyOf') {
while (items.length < minItems) items.push(getBlankOneOf(schema.items, getRef));
return items;
}
if (schema.items.widget === 'multiselect') return items;
let default_ = schema.items.default;
if (schema.items.hasOwnProperty('const')) default_ = schema.items.const;
if (type === 'boolean') {
while (items.length < minItems) items.push(default_ === false ? false : default_ || null);
} else if (type === 'integer' || type === 'number') {
while (items.length < minItems) items.push(default_ === 0 ? 0 : default_ || null);
} else {
// string, etc.
while (items.length < minItems) items.push(default_ || '');
}
return items;
}
function getBlankAllOf(schema, getRef) {
// currently, we support allOf only inside an object
return getBlankObject(schema, getRef);
}
function getBlankOneOf(schema, getRef) {
// for blank data, we always return the first option
let nextSchema = schema.oneOf[0];
getSchemaType(nextSchema);
return getBlankData(nextSchema, getRef);
}
function getBlankAnyOf(schema, getRef) {
// for blank data, we always return the first option
let nextSchema = schema.anyOf[0];
getSchemaType(nextSchema);
return getBlankData(nextSchema, getRef);
}
function getBlankData(schema, getRef) {
if (schema.hasOwnProperty('$ref')) {
schema = _extends({}, getRef(schema['$ref']), schema);
delete schema['$ref'];
}
let type = getSchemaType(schema);
let default_ = schema.default;
if (schema.hasOwnProperty('const')) {
type = actualType(schema.const);
default_ = schema.const;
}
if (type === 'array') return getBlankArray(schema, getRef);else if (type === 'object') return getBlankObject(schema, getRef);else if (type === 'allOf') return getBlankAllOf(schema, getRef);else if (type === 'oneOf') return getBlankOneOf(schema, getRef);else if (type === 'anyOf') return getBlankAnyOf(schema, getRef);else if (type === 'boolean') return default_ === false ? false : default_ || null;else if (type === 'integer' || type === 'number') return default_ === 0 ? 0 : default_ || null;else // string, etc.
return default_ || '';
}
function getSyncedArray(data, schema, getRef) {
if (data === null) data = [];
if (actualType(data) !== 'array') throw new Error("Schema expected an 'array' but the data type was '" + actualType(data) + "'");
let newData = JSON.parse(JSON.stringify(data));
if (schema.items.hasOwnProperty('$ref')) {
// :TODO: this will most probably mutate the original schema
// but i'll fix it later
schema.items = _extends({}, getRef(schema.items['$ref']), schema.items);
delete schema.items['$ref'];
}
let type;
let default_;
if (schema.items.hasOwnProperty('const')) {
type = actualType(schema.items.const);
default_ = schema.items.const;
} else {
type = normalizeKeyword(schema.items.type);
default_ = schema.items.defualt;
}
let minItems = schema.minItems || schema.min_items || 0;
if (schema.items.widget !== 'multiselect') {
while (data.length < minItems) data.push(FILLER);
}
for (let i = 0; i < data.length; i++) {
let item = data[i];
if (type === 'array') {
if (item === FILLER) item = [];
newData[i] = getSyncedArray(item, schema.items, getRef);
} else if (type === 'object') {
if (item === FILLER) item = {};
newData[i] = getSyncedObject(item, schema.items, getRef);
} else {
// if the current value is not in choices, we reset to blank
if (!valueInChoices(schema.items, newData[i])) item = FILLER;
if (item === FILLER) {
if (type === 'integer' || type === 'number') newData[i] = default_ === 0 ? 0 : default_ || null;else if (type === 'boolean') newData[i] = default_ === false ? false : default_ || null;else newData[i] = default_ || '';
}
}
if (schema.items.hasOwnProperty('const')) newData[i] = schema.items.const;
}
return newData;
}
function getSyncedObject(data, schema, getRef) {
if (data === null) data = {};
if (actualType(data) !== 'object') throw new Error("Schema expected an 'object' but the data type was '" + actualType(data) + "'");
let newData = JSON.parse(JSON.stringify(data));
let schema_keys = getKeyword(schema, 'keys', 'properties', {});
if (schema.hasOwnProperty('allOf')) {
for (let i = 0; i < schema.allOf.length; i++) {
// ignore items in allOf which are not object
if (getSchemaType(schema.allOf[i]) !== 'object') continue;
schema_keys = _extends({}, schema_keys, getKeyword(schema.allOf[i], 'properties', 'keys', {}));
}
}
let keys = [...Object.keys(schema_keys)];
for (let i = 0; i < keys.length; i++) {
let key = keys[i];
let schemaValue = schema_keys[key];
let isRef = schemaValue.hasOwnProperty('$ref');
if (isRef) {
schemaValue = _extends({}, getRef(schemaValue['$ref']), schemaValue);
delete schemaValue['$ref'];
}
let type;
let default_;
if (schemaValue.hasOwnProperty('const')) {
type = actualType(schemaValue.const);
default_ = schemaValue.const;
} else {
type = getSchemaType(schemaValue);
default_ = schemaValue.default;
}
if (!data.hasOwnProperty(key)) {
/* This key is declared in schema but it's not present in the data.
So we can use blank data here.
*/
if (type === 'array') newData[key] = getSyncedArray([], schemaValue, getRef);else if (type === 'object') newData[key] = getSyncedObject({}, schemaValue, getRef);else if (type === 'oneOf') newData[key] = getBlankOneOf(schemaValue, getRef);else if (type === 'anyOf') newData[key] = getBlankAnyOf(schemaValue, getRef);else if (type === 'boolean') newData[key] = default_ === false ? false : default_ || null;else if (type === 'integer' || type === 'number') newData[key] = default_ === 0 ? 0 : default_ || null;else newData[key] = default_ || '';
} else {
if (type === 'array') newData[key] = getSyncedArray(data[key], schemaValue, getRef);else if (type === 'object') newData[key] = getSyncedObject(data[key], schemaValue, getRef);else if (type === 'oneOf') newData[key] = getSyncedOneOf(data[key], schemaValue, getRef);else if (type === 'anyOf') newData[key] = getSyncedAnyOf(data[key], schemaValue, getRef);else {
// if the current value is not in choices, we reset to blank
if (!valueInChoices(schemaValue, data[key])) data[key] = '';
if (data[key] === '') {
if (type === 'integer' || type === 'number') newData[key] = default_ === 0 ? 0 : default_ || null;else if (type === 'boolean') newData[key] = default_ === false ? false : default_ || null;else newData[key] = default_ || '';
} else {
newData[key] = data[key];
}
}
}
if (schemaValue.hasOwnProperty('const')) newData[key] = schemaValue.const;
}
if (schema.hasOwnProperty('oneOf')) newData = _extends({}, newData, getSyncedOneOf(data, schema, getRef));
if (schema.hasOwnProperty('anyOf')) newData = _extends({}, newData, getSyncedAnyOf(data, schema, getRef));
return newData;
}
function getSyncedAllOf(data, schema, getRef) {
// currently we only support allOf inside an object
// so, we'll treat the curent schema and data to be an object
return getSyncedObject(data, schema, getRef);
}
function getSyncedOneOf(data, schema, getRef) {
let index = findMatchingSubschemaIndex(data, schema, getRef, 'oneOf');
let subschema = schema['oneOf'][index];
let syncFunc = getSyncFunc(getSchemaType(subschema));
if (syncFunc) return syncFunc(data, subschema, getRef);
return data;
}
function getSyncedAnyOf(data, schema, getRef) {
let index = findMatchingSubschemaIndex(data, schema, getRef, 'anyOf');
let subschema = schema['anyOf'][index];
let syncFunc = getSyncFunc(getSchemaType(subschema));
if (syncFunc) return syncFunc(data, subschema, getRef);
return data;
}
function getSyncedData(data, schema, getRef) {
// adds those keys to data which are in schema but not in data
if (schema.hasOwnProperty('$ref')) {
schema = _extends({}, getRef(schema['$ref']), schema);
delete schema['$ref'];
}
let type = getSchemaType(schema);
let syncFunc = getSyncFunc(type);
if (syncFunc) return syncFunc(data, schema, getRef);
return data;
}
function getSyncFunc(type) {
if (type === 'array') return getSyncedArray;else if (type === 'object') return getSyncedObject;else if (type === 'allOf') return getSyncedAllOf;else if (type === 'oneOf') return getSyncedOneOf;else if (type === 'anyOf') return getSyncedAnyOf;
return null;
}
function findMatchingSubschemaIndex(data, schema, getRef, schemaName) {
let dataType = actualType(data);
let subschemas = schema[schemaName];
let index = null;
for (let i = 0; i < subschemas.length; i++) {
let subschema = subschemas[i];
if (subschema.hasOwnProperty('$ref')) {
subschema = _extends({}, getRef(subschema['$ref']), subschema);
delete subschema['$ref'];
}
let subType = getSchemaType(subschema);
if (dataType === 'object') {
// check if all keys match
if (dataObjectMatchesSchema(data, subschema)) {
index = i;
break;
}
} else if (dataType === 'array') {
// check if item types match
if (dataArrayMatchesSchema(data, subschema)) {
index = i;
break;
}
} else if (dataType === subType) {
index = i;
break;
}
}
if (index === null) {
// no exact match found
// so we'll just return the first schema that matches the data type
for (let i = 0; i < subschemas.length; i++) {
let subschema = subschemas[i];
if (subschema.hasOwnProperty('$ref')) {
subschema = _extends({}, getRef(subschema['$ref']), subschema);
delete subschema['$ref'];
}
let subType = getSchemaType(subschema);
if (dataType === subType) {
index = i;
break;
}
}
}
if (index === null) {
// still no match found
if (data === null) // for null data, return the first subschema and hope for the best
index = 0;else // for anything else, throw error
throw new Error("No matching subschema found in '" + schemaName + "' for data '" + data + "' (type: " + dataType + ")");
}
return index;
}
function dataObjectMatchesSchema(data, subschema) {
let dataType = actualType(data);
let subType = getSchemaType(subschema);
if (subType !== dataType) return false;
let subSchemaKeys = getKeyword(subschema, 'properties', 'keys', {}); // check if all keys in the schema are present in the data
keyset1 = new Set(Object.keys(data));
keyset2 = new Set(Object.keys(subSchemaKeys));
if (subschema.hasOwnProperty('additionalProperties')) {
// subSchemaKeys must be a subset of data
if (!isSubset(keyset2, keyset1)) return false;
} else {
// subSchemaKeys must be equal to data
if (!isEqualset(keyset2, keyset1)) return false;
}
for (let key in subSchemaKeys) {
if (!subSchemaKeys.hasOwnProperty(key)) continue;
if (!data.hasOwnProperty(key)) return false;
if (subSchemaKeys[key].hasOwnProperty('const')) {
if (subSchemaKeys[key].const !== data[key]) return false;
}
let keyType = normalizeKeyword(subSchemaKeys[key].type);
let dataValueType = actualType(data[key]);
if (keyType === 'number' && ['number', 'integer', 'null'].indexOf(dataValueType) === -1) {
return false;
} else if (keyType === 'integer' && ['number', 'integer', 'null'].indexOf(dataValueType) === -1) {
return false;
} else if (keyType === 'boolean' && ['boolean', 'null'].indexOf(dataValueType) === -1) {
return false;
} else if (keyType === 'string' && dataValueType !== 'string') {
return false;
} // TODO: also check minimum, maximum, etc. keywords
} // if here, all checks have passed
return true;
}
function dataArrayMatchesSchema(data, subschema) {
let dataType = actualType(data);
let subType = getSchemaType(subschema);
if (subType !== dataType) return false;
let itemsType = subschema.items.type; // Temporary. Nested subschemas inside array.items won't work.
// check each item in data conforms to array items.type
for (let i = 0; i < data.length; i++) {
dataValueType = actualType(data[i]);
if (subschema.items.hasOwnProperty('const')) {
if (subschema.items.const !== data[i]) return false;
}
if (itemsType === 'number' && ['number', 'integer', 'null'].indexOf(dataValueType) === -1) {
return false;
} else if (itemsType === 'integer' && ['number', 'integer', 'null'].indexOf(dataValueType) === -1) {
return false;
} else if (itemsType === 'boolean' && ['boolean', 'null'].indexOf(dataValueType) === -1) {
return false;
} else if (itemsType === 'string' && dataValueType !== 'string') {
return false;
}
} // if here, all checks have passed
return true;
}
const _excluded$2 = ["className", "alterClassName"];
function Button(_ref) {
let {
className,
alterClassName
} = _ref,
props = _objectWithoutPropertiesLoose(_ref, _excluded$2);
if (!className) className = '';
let classes = className.split(' ');
if (alterClassName !== false) {
className = '';
for (let i = 0; i < classes.length; i++) {
className = className + 'rjf-' + classes[i] + '-button ';
}
}
return /*#__PURE__*/React.createElement("button", _extends({
className: className.trim(),
type: "button"
}, props), props.children);
}
function Loader(props) {
let className = 'rjf-loader';
if (props.className) className = className + ' ' + props.className;
return /*#__PURE__*/React.createElement("div", {
className: className
});
}
function Icon(props) {
let icon;
switch (props.name) {
case 'chevron-up':
icon = /*#__PURE__*/React__default["default"].createElement(ChevronUp, null);
break;
case 'chevron-down':
icon = /*#__PURE__*/React__default["default"].createElement(ChevronDown, null);
break;
case 'arrow-down':
icon = /*#__PURE__*/React__default["default"].createElement(ArrowDown, null);
break;
case 'x-lg':
icon = /*#__PURE__*/React__default["default"].createElement(XLg, null);
break;
case 'x-circle':
icon = /*#__PURE__*/React__default["default"].createElement(XCircle, null);
break;
case 'three-dots-vertical':
icon = /*#__PURE__*/React__default["default"].createElement(ThreeDotsVertical, null);
break;
case 'box-arrow-up-right':
icon = /*#__PURE__*/React__default["default"].createElement(BoxArrowUpRight, null);
break;
}
return /*#__PURE__*/React__default["default"].createElement("svg", {
xmlns: "http://www.w3.org/2000/svg",
width: "16",
height: "16",
fill: "currentColor",
className: "rjf-icon rjf-icon-" + props.name,
viewBox: "0 0 16 16"
}, icon);
}
function ChevronUp(props) {
return /*#__PURE__*/React__default["default"].createElement("path", {
fillRule: "evenodd",
d: "M7.646 4.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1-.708.708L8 5.707l-5.646 5.647a.5.5 0 0 1-.708-.708l6-6z"
});
}
function ChevronDown(props) {
return /*#__PURE__*/React__default["default"].createElement("path", {
fillRule: "evenodd",
d: "M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z"
});
}
function ArrowDown(props) {
return /*#__PURE__*/React__default["default"].createElement("path", {
"fill-rule": "evenodd",
d: "M8 1a.5.5 0 0 1 .5.5v11.793l3.146-3.147a.5.5 0 0 1 .708.708l-4 4a.5.5 0 0 1-.708 0l-4-4a.5.5 0 0 1 .708-.708L7.5 13.293V1.5A.5.5 0 0 1 8 1z"
});
}
function XLg(props) {
return /*#__PURE__*/React__default["default"].createElement("path", {
d: "M2.146 2.854a.5.5 0 1 1 .708-.708L8 7.293l5.146-5.147a.5.5 0 0 1 .708.708L8.707 8l5.147 5.146a.5.5 0 0 1-.708.708L8 8.707l-5.146 5.147a.5.5 0 0 1-.708-.708L7.293 8 2.146 2.854Z"
});
}
function XCircle(props) {
return /*#__PURE__*/React__default["default"].createElement(React__default["default"].Fragment, null, /*#__PURE__*/React__default["default"].createElement("path", {
d: "M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"
}), /*#__PURE__*/React__default["default"].createElement("path", {
d: "M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z"
}));
}
function ThreeDotsVertical(props) {
return /*#__PURE__*/React__default["default"].createElement("path", {
d: "M9.5 13a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0z"
});
}
function BoxArrowUpRight(props) {
return /*#__PURE__*/React__default["default"].createElement(React__default["default"].Fragment, null, /*#__PURE__*/React__default["default"].createElement("path", {
"fill-rule": "evenodd",
d: "M8.636 3.5a.5.5 0 0 0-.5-.5H1.5A1.5 1.5 0 0 0 0 4.5v10A1.5 1.5 0 0 0 1.5 16h10a1.5 1.5 0 0 0 1.5-1.5V7.864a.5.5 0 0 0-1 0V14.5a.5.5 0 0 1-.5.5h-10a.5.5 0 0 1-.5-.5v-10a.5.5 0 0 1 .5-.5h6.636a.5.5 0 0 0 .5-.5"
}), /*#__PURE__*/React__default["default"].createElement("path", {
"fill-rule": "evenodd",
d: "M16 .5a.5.5 0 0 0-.5-.5h-5a.5.5 0 0 0 0 1h3.793L6.146 9.146a.5.5 0 1 0 .708.708L15 1.707V5.5a.5.5 0 0 0 1 0z"
}));
}
class TimePicker extends React__default["default"].Component {
constructor(...args) {
super(...args);
this.sendValue = data => {
this.props.onChange(data);
};
this.validateValue = (name, value) => {
if (name === 'hh' && value < 1) return 12;else if (name !== 'hh' && value < 0) return 59;else if (name === 'hh' && value > 12) return 1;else if (name !== 'hh' && value > 59) return 0;
return value;
};
this.handleChange = e => {
let name = e.target.dataset.name;
let value = e.target.value;
if (isNaN(value)) return;
let validValue = this.validateValue(name, parseInt(value) || 0);
if (name === 'hh' && (value === '0' || value === '' || value === '00') && validValue === 1) validValue = 0;
if (value.startsWith('0') && validValue < 10 && validValue !== 0) {
validValue = validValue.toString().padStart(2, '0');
}
this.sendValue({
[name]: value !== '' ? validValue.toString() : ''
});
};
this.handleKeyDown = e => {
if (e.keyCode !== 38 && e.keyCode !== 40) return;
let name = e.target.dataset.name;
let value = parseInt(e.target.value) || 0;
if (e.keyCode === 38) {
value++;
} else if (e.keyCode === 40) {
value--;
}
this.sendValue({
[name]: this.validateValue(name, value).toString().padStart(2, '0')
});
};
this.handleSpin = (name, type) => {
let value = this.props[name];
if (name === 'ampm') {
value = value === 'am' ? 'pm' : 'am';
} else {
value = parseInt(value) || 0;
if (type === 'up') {
value++;
} else {
value--;
}
value = this.validateValue(name, value).toString().padStart(2, '0');
}
this.sendValue({
[name]: value
});
};
this.handleBlur = e => {
let value = this.validateValue(e.target.dataset.name, parseInt(e.target.value) || 0);
if (value < 10) {
this.sendValue({
[e.target.dataset.name]: value.toString().padStart(2, '0')
});
}
};
}
componentWillUnmount() {
let data = {
hh: this.validateValue('hh', this.props.hh).toString().padStart(2, '0'),
mm: this.validateValue('mm', this.props.mm).toString().padStart(2, '0'),
ss: this.validateValue('ss', this.props.ss).toString().padStart(2, '0')
};
this.sendValue(data);
}
render() {
return /*#__PURE__*/React__default["default"].createElement("div", {
className: "rjf-time-picker"
}, /*#__PURE__*/React__default["default"].createElement("div", {
className: "rjf-time-picker-row rjf-time-picker-labels"
}, /*#__PURE__*/React__default["default"].createElement("div", {
className: "rjf-time-picker-col"
}, "Hrs"), /*#__PURE__*/React__default["default"].createElement("div", {
className: "rjf-time-picker-col rjf-time-picker-col-sm"
}), /*#__PURE__*/React__default["default"].createElement("div", {
className: "rjf-time-picker-col"
}, "Min"), /*#__PURE__*/React__default["default"].createElement("div", {
className: "rjf-time-picker-col rjf-time-picker-col-sm"
}), /*#__PURE__*/React__default["default"].createElement("div", {
className: "rjf-time-picker-col"
}, "Sec"), /*#__PURE__*/React__default["default"].createElement("div", {
className: "rjf-time-picker-col rjf-time-picker-col-sm"
}), /*#__PURE__*/React__default["default"].createElement("div", {
className: "rjf-time-picker-col"
}, "am/pm")), /*#__PURE__*/React__default["default"].createElement("div", {
className: "rjf-time-picker-row"
}, /*#__PURE__*/React__default["default"].createElement("div", {
className: "rjf-time-picker-col"
}, /*#__PURE__*/React__default["default"].createElement(Button, {
onClick: () => this.handleSpin('hh', 'up')
}, /*#__PURE__*/React__default["default"].createElement(Icon, {
name: "chevron-up"
}))), /*#__PURE__*/React__default["default"].createElement("div", {
className: "rjf-time-picker-col rjf-time-picker-col-sm"
}), /*#__PURE__*/React__default["default"].createElement("div", {
className: "rjf-time-picker-col"
}, /*#__PURE__*/React__default["default"].createElement(Button, {
onClick: () => this.handleSpin('mm', 'up')
}, /*#__PURE__*/React__default["default"].createElement(Icon, {
name: "chevron-up"
}))), /*#__PURE__*/React__default["default"].createElement("div", {
className: "rjf-time-picker-col rjf-time-picker-col-sm"
}), /*#__PURE__*/React__default["default"].createElement("div", {
className: "rjf-time-picker-col"
}, /*#__PURE__*/React__default["default"].createElement(Button, {
onClick: () => this.handleSpin('ss', 'up')
}, /*#__PURE__*/React__default["default"].createElement(Icon, {
name: "chevron-up"
}))), /*#__PURE__*/React__default["default"].createElement("div", {
className: "rjf-time-picker-col rjf-time-picker-col-sm"
}), /*#__PURE__*/React__default["default"].createElement("div", {
className: "rjf-time-picker-col"
}, /*#__PURE__*/React__default["default"].createElement(Button, {
onClick: () => this.handleSpin('ampm', 'up')
}, /*#__PURE__*/React__default["default"].createElement(Icon, {
name: "chevron-up"
})))), /*#__PURE__*/React__default["default"].createElement("div", {
className: "rjf-time-picker-row rjf-time-picker-values"
}, /*#__PURE__*/React__default["default"].createElement("div", {
className: "rjf-time-picker-col"
}, /*#__PURE__*/React__default["default"].createElement("input", {
type: "text",
"data-name": "hh",
value: this.props.hh,
onChange: this.handleChange,
onBlur: this.handleBlur,
onKeyDown: this.handleKeyDown
})), /*#__PURE__*/React__default["default"].createElement("div", {
className: "rjf-time-picker-col rjf-time-picker-col-sm"
}, ":"), /*#__PURE__*/React__default["default"].createElement("div", {
className: "rjf-time-picker-col"
}, /*#__PURE__*/React__default["default"].createElement("input", {
type: "text",
"data-name": "mm",
value: this.props.mm,
onChange: this.handleChange,
onBlur: this.handleBlur,
onKeyDown: this.handleKeyDown
})), /*#__PURE__*/React__default["default"].createElement("div", {
className: "rjf-time-picker-col rjf-time-picker-col-sm"
}, ":"), /*#__PURE__*/React__default["default"].createElement("div", {
className: "rjf-time-picker-col"
}, /*#__PURE__*/React__default["default"].createElement("input", {
type: "text",
"data-name": "ss",
value: this.props.ss,
onChange: this.handleChange,
onBlur: this.handleBlur,
onKeyDown: this.handleKeyDown
})), /*#__PURE__*/React__default["default"].createElement("div", {
className: "rjf-time-picker-col rjf-time-picker-col-sm"
}), /*#__PURE__*/React__default["default"].createElement("div", {
className: "rjf-time-picker-col"
}, this.props.ampm)), /*#__PURE__*/React__default["default"].createElement("div", {
className: "rjf-time-picker-row"
}, /*#__PURE__*/React__default["default"].createElement("div", {
className: "rjf-time-picker-col"
}, /*#__PURE__*/React__default["default"].createElement(Button, {
onClick: () => this.handleSpin('hh', 'down')
}, /*#__PURE__*/React__default["default"].createElement(Icon, {
name: "chevron-down"
}))), /*#__PURE__*/React__default["default"].createElement("div", {
className: "rjf-time-picker-col rjf-time-picker-col-sm"
}), /*#__PURE__*/React__default["default"].createElement("div", {
className: "rjf-time-picker-col"
}, /*#__PURE__*/React__default["default"].createElement(Button, {
onClick: () => this.handleSpin('mm', 'down')
}, /*#__PURE__*/React__default["default"].createElement(Icon, {
name: "chevron-down"
}))), /*#__PURE__*/React__default["default"].createElement("div", {
className: "rjf-time-picker-col rjf-time-picker-col-sm"
}), /*#__PURE__*/React__default["default"].createElement("div", {
className: "rjf-time-picker-col"
}, /*#__PURE__*/React__default["default"].createElement(Button, {
onClick: () => this.handleSpin('ss', 'down')
}, /*#__PURE__*/React__default["default"].createElement(Icon, {
name: "chevron-down"
}))), /*#__PURE__*/React__default["default"].createElement("div", {
className: "rjf-time-picker-col rjf-time-picker-col-sm"
}), /*#__PURE__*/React__default["default"].createElement("div", {
className: "rjf-time-picker-col"
}, /*#__PURE__*/React__default["default"].createElement(Button, {
onClick: () => this.handleSpin('ampm', 'down')
}, /*#__PURE__*/React__default["default"].createElement(Icon, {
name: "chevron-down"
})))));
}
}
const _excluded$1 = ["label", "help_text", "error", "inputRef"],
_excluded2 = ["label", "help_text", "error", "value"],
_excluded3 = ["label", "help_text", "error", "value", "options"],
_excluded4 = ["label", "help_text", "error", "value", "options"],
_excluded5 = ["label", "value"],
_excluded6 = ["label", "help_text", "error", "inputRef"];
function Label(props) {
if (!props.label) return null;
return /*#__PURE__*/React__default["default"].createElement("label", {
className: props.required ? 'rjf-required' : null
}, props.children, props.children && ' ', props.label);
}
function FormInput(_ref) {
let {
label,
help_text,
error,
inputRef
} = _ref,
props = _objectWithoutPropertiesLoose(_ref, _excluded$1);
if (props.type === 'string') props.type = 'text';
if (inputRef) props.ref = inputRef;
if (props.value === null) props.value = '';
let wrapperProps = {};
if (props.type == 'hidden') wrapperProps['style'] = {
display: 'none'
}; // readonly inputs are automatically marked disabled
// if this is undesired, explicitly pass disabled=false
if (props.readOnly && (props.disabled === undefined || props.disabled === null)) props.disabled = true;
return /*#__PURE__*/React__default["default"].createElement("div", wrapperProps, /*#__PURE__*/React__default["default"].createElement(Label, {
label: label,
required: props.required
}), /*#__PURE__*/React__default["default"].createElement("div", {
className: error ? "rjf-input-group has-error" : "rjf-input-group"
}, props.children || /*#__PURE__*/React__default["default"].createElement("input", props), error && error.map((error, i) => /*#__PURE__*/React__default["default"].createElement("span", {
className: "rjf-error-text",
key: i
}, error)), help_text && /*#__PURE__*/React__default["default"].createElement("span", {
className: "rjf-help-text"
}, help_text)));
}
function FormCheckInput(_ref2) {
let {
label,
help_text,
error,
value
} = _ref2,
props = _objectWithoutPropertiesLoose(_ref2, _excluded2);
if (!label) label = props.name.toUpperCase();
if (props.type === 'bool') props.type = 'checkbox';
if (props.checked === undefined) props.checked = value;
if (props.checked === '' || props.checked === null || props.checked === undefined) props.checked = false;
if (props.readOnly) props.disabled = true;
return /*#__PURE__*/React__default["default"].createElement("div", {
className: error ? "rjf-check-input has-error" : "rjf-check-input"
}, /*#__PURE__*/React__default["default"].createElement(Label, {
label: label,
required: props.required
}, /*#__PURE__*/React__default["default"].createElement("input", props)), error && error.map((error, i) => /*#__PURE__*/React__default["default"].createElement("span", {
className: "rjf-error-text",
key: i
}, error)), help_text && /*#__PURE__*/React__default["default"].createElement("span", {
className: "rjf-help-text"
}, help_text));
}
function FormRadioInput(_ref3) {
let {
label,
help_text,
error,
value,
options
} = _ref3,
props = _objectWithoutPropertiesLoose(_ref3, _excluded3);
if (props.readOnly) props.disabled = true;
return /*#__PURE__*/React__default["default"].createElement("div", {
className: error ? "rjf-check-input has-error" : "rjf-check-input"
}, /*#__PURE__*/React__default["default"].createElement(Label, {
label: label,
required: props.required
}), options.map((option, i) => {
let title, inputValue;
if (typeof option === 'object') {
title = option.title || option.label;
inputValue = option.value;
} else {
title = option;
if (typeof title === 'boolean') title = capitalize$1(title.toString());
inputValue = option;
}
return /*#__PURE__*/React__default["default"].createElement("label", {
className: "rjf-radio-option",
key: title + '_' + inputValue + '_' + i
}, /*#__PURE__*/React__default["default"].createElement("input", _extends({}, props, {
value: inputValue,
checked: inputValue === value
})), " ", title);
}), error && error.map((error, i) => /*#__PURE__*/React__default["default"].createElement("span", {
className: "rjf-error-text",
key: i
}, error)), help_text && /*#__PURE__*/React__default["default"].createElement("span", {
className: "rjf-help-text"
}, help_text));
}
function FormSelectInput(_ref4) {
let {
label,
help_text,
error,
value,
options
} = _ref4,
props = _objectWithoutPropertiesLoose(_ref4, _excluded4);
if (props.readOnly) props.disabled = true;
if (!value && value !== false && value !== 0) value = '';
return /*#__PURE__*/React__default["default"].createElement("div", null, /*#__PURE__*/React__default["default"].createElement(Label, {
label: label,
required: props.required
}), /*#__PURE__*/React__default["default"].createElement("div", {
className: error ? "rjf-input-group has-error" : "rjf-input-group"
}, /*#__PURE__*/React__default["default"].createElement("select", _extends({
value: value
}, props), /*#__PURE__*/React__default["default"].createElement("option", {
disabled: true,
value: "",
key: '__placeholder'
}, "Select..."), options.map((option, i) => {
let title, inputValue;
if (typeof option === 'object') {
title = option.title || option.label;
inputValue = option.value;
} else {
title = option;
if (typeof title === 'boolean') title = capitalize$1(title.toString());
inputValue = option;
}
return /*#__PURE__*/React__default["default"].createElement("option", {
value: inputValue,
key: title + '_' + inputValue + '_' + i
}, title);
})), error && error.map((error, i) => /*#__PURE__*/React__default["default"].createElement("span", {
className: "rjf-error-text",
key: i
}, error)), help_text && /*#__PURE__*/React__default["default"].createElement("span", {
className: "rjf-help-text"
}, help_text)));
}
class FormMultiSelectInput extends React__default["default"].Component {
constructor(props) {
super(props);
this.handleChange = e => {
let value = [...this.props.value];
let val = e.target.value;
if (typeof val !== this.props.valueType) val = convertType(val, this.props.valueType);
if (e.target.checked) {
value.push(val);
} else {
value = value.filter(item => {
return item !== val;
});
}
let event = {
target: {
type: this.props.type,
value: value,
name: this.props.name
}
};
this.props.onChange(event);
};
this.showOptions = e => {
if (!this.state.showOptions) this.setState({
showOptions: true
});
};
this.hideOptions = e => {
this.setState({
showOptions: false
});
};
this.toggleOptions = e => {
this.setState(state => ({
showOptions: !state.showOptions
}));
};
this.state = {
showOptions: false
};
this.optionsContainer = /*#__PURE__*/React__default["default"].createRef();
this.input = /*#__PURE__*/React__default["default"].createRef();
}
render() {
return /*#__PURE__*/React__default["default"].createElement("div", {
className: this.props.readOnly ? "rjf-multiselect-field readonly" : "rjf-multiselect-field"
}, /*#__PURE__*/React__default["default"].createElement(FormInput, {
label: this.props.label,
help_text: this.props.help_text,
error: this.props.error
}, /*#__PURE__*/React__default["default"].createElement(FormMultiSelectInputField, {
inputRef: this.input,
onClick: this.toggleOptions,
value: this.props.value,
options: this.props.options,
onChange: this.handleChange,
disabled: this.props.readOnly,
placeholder: this.props.placeholder
})), this.state.showOptions && /*#__PURE__*/React__default["default"].createElement(FormMultiSelectInputOptions, {
options: this.props.options,
value: this.props.value,
hideOptions: this.hideOptions,
onChange: this.handleChange,
containerRef: this.optionsContainer,
inputRef: this.input,
disabled: this.props.readOnly,
hasHelpText: (this.props.help_text || this.props.error) && 1
}));
}
}
class FormMultiSelectInputField extends React__default["default"].Component {
constructor(...args) {
super(...args);
this.handleRemove = (e, index) => {
e.stopPropagation(); // we create a fake event object for the onChange handler
let event = {
target: {
value: this.props.value[index],
checked: false
}
};
this.props.onChange(event);
};
}
render() {
let valueTitleMap = choicesValueTitleMap(this.props.options || this.props.value);
return /*#__PURE__*/React__default["default"].createElement("div", {
className: "rjf-multiselect-field-input",
onClick: this.props.onClick,
ref: this.props.inputRef,
tabIndex: 0
}, this.props.value.length ? this.props.value.map((item, index) => /*#__PURE__*/React__default["default"].createElement("span", {
className: "rjf-multiselect-field-input-item",
key: item + '_' + index
}, /*#__PURE__*/React__default["default"].createElement("span", null, valueTitleMap[item]), this.props.disabled || /*#__PURE__*/React__default["default"].createElement("button", {
title: "Remove",
type: "button",
onClick: e => this.handleRemove(e, index)
}, "\xD7"))) : /*#__PURE__*/React__default["default"].createElement("span", {
className: "rjf-multiselect-field-input-placeholder"
}, this.props.placeholder || 'Select...'));
}
}
class FormMultiSelectInputOptions extends React__default["default"].Component {
constructor(...args) {
super(...args);
this.handleClickOutside = e => {
if (this.props.containerRef.current && !this.props.containerRef.current.contains(e.target) && !this.props.inputRef.current.contains(e.target)) this.props.hideOptions();
};
}
componentDidMount() {
document.addEventListener('mousedown', this.handleClickOutside);
}
componentWillUnmount() {
document.removeEventListener('mousedown', this.handleClickOutside);
}
render() {
return /*#__PURE__*/React__default["default"].createElement("div", {
ref: this.props.containerRef
}, /*#__PURE__*/React__default["default"].createElement("div", {
className: "rjf-multiselect-field-options-container",
style: this.props.hasHelpText ? {
marginTop: '-15px'
} : {}
}, this.props.options.map((option, i) => {
let title, inputValue;
if (typeof option === 'object') {
title = option.title || option.label;
inputValue = option.value;
} else {
title = option;
if (typeof title === 'boolean') title = capitalize$1(title.toString());
inputValue = option;
}
let selected = this.props.value.indexOf(inputValue) > -1;
let optionClassName = 'rjf-multiselect-field-option';
if (selected) optionClassName += ' selected';
if (this.props.disabled) optionClassName += ' disabled';
return /*#__PURE__*/React__default["default"].createElement("div", {
key: title + '_' + inputValue + '_' + i,
className: optionClassName
}, /*#__PURE__*/React__default["default"].createElement("label", null, /*#__PURE__*/React__default["default"].createElement("input", {
type: "checkbox",
onChange: this.props.onChange,
value: inputValue,
checked: selected,
disabled: this.props.disabled
}), " ", title));
})));
}
}
function dataURItoBlob(dataURI) {
// Split metadata from data
const splitted = dataURI.split(","); // Split params
const params = splitted[0].split(";"); // Get mime-type from params
const type = params[0].replace("data:", ""); // Filter the name property from params
const properties = params.filter(param => {
return param.split("=")[0] === "name";
}); // Look for the name and use unknown if no name property.
let name;
if (properties.length !== 1) {
name = "unknown";
} else {
// Because we filtered out the other property,
// we only have the name case here.
name = properties[0].split("=")[1];
} // Built the Uint8Array Blob parameter from the base64 string.
const binary = atob(splitted[1]);
const array = [];
for (let i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
} // Create the blob object
const blob = new window.Blob([new Uint8Array(array)], {
type
});
return {
blob,
name
};
}
class FormFileInput extends React__default["default"].Component {
constructor(props) {
super(props);
this.getFileName = () => {
if (!this.props.value) return '';
if (this.props.type === 'data-url') {
return this.extractFileInfo(this.props.value).name;
} else if (this.props.type === 'file-url') {
return this.props.value;
} else {
return 'Unknown file';
}
};
this.extractFileInfo = dataURL => {
const {
blob,
name
} = dataURItoBlob(dataURL);
return {
name: name,
size: blob.size,
type: blob.type
};
};
this.addNameToDataURL = (dataURL, name) => {
return dataURL.replace(';base64', ';name=' + encodeURIComponent(name) + ';base64');
};
this.handleChange = e => {
if (this.props.type === 'data-url') {
let file = e.target.files[0];
let fileName = file.name;
let reader = new FileReader();
reader.onload = () => {
// this.setState({src: reader.result});
// we create a fake event object