"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __rest = (this && this.__rest) || function (s, e) {
    var t = {};
    for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
        t[p] = s[p];
    if (s != null && typeof Object.getOwnPropertySymbols === "function")
        for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
            if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
                t[p[i]] = s[p[i]];
        }
    return t;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.classNames = exports.getFieldUUID = exports.getUUID = exports.assignUUID = exports.idSchemaIdToJSONPointer = exports.JSONPointerToId = exports.formatErrorMessage = exports.keyboardClick = exports.formDataEquals = exports.formDataIsEmpty = exports.filterItemIdsDeeply = exports.filterItemId = exports.filterLajiFormId = exports.syncScroll = exports._syncScroll = exports.shouldSyncScroll = exports.focusAndScroll = exports.focusById = exports.getSchemaElementById = exports.findNearestParentSchemaElemId = exports.focusNextInput = exports.getNextInput = exports.getNextInputInInputs = exports.ReactUtils = exports.isObject = void 0;
exports.isHidden = isHidden;
exports.isDefaultData = isDefaultData;
exports.getDefaultFormState = getDefaultFormState;
exports.hasData = hasData;
exports.propertyHasData = propertyHasData;
exports.getUpdateObjectFromJSONPath = getUpdateObjectFromJSONPath;
exports.getUpdateObjectFromJSONPointer = getUpdateObjectFromJSONPointer;
exports.immutableDelete = immutableDelete;
exports.getUiOptions = getUiOptions;
exports.getInnerUiSchema = getInnerUiSchema;
exports.isNullOrUndefined = isNullOrUndefined;
exports.isEmptyString = isEmptyString;
exports.parseJSONPointer = parseJSONPointer;
exports.getReactComponentName = getReactComponentName;
exports.isMultiSelect = isMultiSelect;
exports.isSelect = isSelect;
exports.getTabbableFields = getTabbableFields;
exports.isTabbableInput = isTabbableInput;
exports.canFocusNextInput = canFocusNextInput;
exports.findNearestParentSchemaElem = findNearestParentSchemaElem;
exports.findNearestParentTabbableElem = findNearestParentTabbableElem;
exports.getNestedTailUiSchema = getNestedTailUiSchema;
exports.updateTailUiSchema = updateTailUiSchema;
exports.getNestedUiFieldsList = getNestedUiFieldsList;
exports.getBootstrapCols = getBootstrapCols;
exports.isDescendant = isDescendant;
exports.getKeyHandlerTargetId = getKeyHandlerTargetId;
exports.capitalizeFirstLetter = capitalizeFirstLetter;
exports.decapitalizeFirstLetter = decapitalizeFirstLetter;
exports.stringifyKeyCombo = stringifyKeyCombo;
exports.canAdd = canAdd;
exports.bsSizeToPixels = bsSizeToPixels;
exports.pixelsToBsSize = pixelsToBsSize;
exports.applyFunction = applyFunction;
exports.getWindowScrolled = getWindowScrolled;
exports.getScrollPositionForScrollIntoViewIfNeeded = getScrollPositionForScrollIntoViewIfNeeded;
exports.scrollIntoViewIfNeeded = scrollIntoViewIfNeeded;
exports.filter = filter;
exports.updateSafelyWithJSONPath = updateSafelyWithJSONPath;
exports.updateSafelyWithJSONPointer = updateSafelyWithJSONPointer;
exports.injectButtons = injectButtons;
exports.dictionarify = dictionarify;
exports.formatValue = formatValue;
exports.checkRules = checkRules;
exports.checkArrayRules = checkArrayRules;
exports.bringRemoteFormData = bringRemoteFormData;
exports.triggerParentComponent = triggerParentComponent;
exports.parseSchemaFromFormDataPointer = parseSchemaFromFormDataPointer;
exports.parseUiSchemaFromFormDataPointer = parseUiSchemaFromFormDataPointer;
exports.checkJSONPointer = checkJSONPointer;
exports.schemaJSONPointer = schemaJSONPointer;
exports.uiSchemaJSONPointer = uiSchemaJSONPointer;
exports.updateFormDataWithJSONPointer = updateFormDataWithJSONPointer;
exports.addLajiFormIds = addLajiFormIds;
exports.getAllLajiFormIdsDeeply = getAllLajiFormIdsDeeply;
exports.removeLajiFormIds = removeLajiFormIds;
exports.findPointerForLajiFormId = findPointerForLajiFormId;
exports.highlightElem = highlightElem;
exports.filteredErrors = filteredErrors;
exports.constructTranslations = constructTranslations;
exports.getIdxWithOffset = getIdxWithOffset;
exports.getIdxWithoutOffset = getIdxWithoutOffset;
exports.getFormDataIndex = getFormDataIndex;
exports.getReversedFormDataIndex = getReversedFormDataIndex;
exports.toJSONPointer = toJSONPointer;
exports.getTitle = getTitle;
exports.translate = translate;
exports.useBooleanSetter = useBooleanSetter;
exports.usePrevious = usePrevious;
exports.asArray = asArray;
exports.getLajiUri = getLajiUri;
const React = __importStar(require("react"));
const react_dom_1 = require("react-dom");
const utils_1 = require("@rjsf/utils");
const Context_1 = __importDefault(require("./Context"));
const ReactContext_1 = __importDefault(require("./ReactContext"));
const immutability_helper_1 = __importDefault(require("immutability-helper"));
const utils_2 = require("@luomus/laji-map/lib/utils");
const deepEquals = require("deep-equal");
const validator_ajv6_1 = __importDefault(require("@rjsf/validator-ajv6"));
exports.isObject = utils_2.isObject;
function isHidden(uiSchema, property) {
    if (!uiSchema)
        return false;
    if (uiSchema[property])
        uiSchema = uiSchema[property];
    return !uiSchema || uiSchema["ui:widget"] == "HiddenWidget" || uiSchema["ui:field"] == "HiddenField";
}
function isDefaultData(formData, schema) {
    switch (schema.type) {
        case "object":
            return !formData || Object.keys(schema.properties).every(field => isDefaultData(formData[field], schema.properties[field]));
        case "array":
            return (Array.isArray(formData) || formData === undefined) && (formData || []).every((item) => isDefaultData(item, schema.items));
        default:
            return formData === getDefaultFormState(schema);
    }
}
function getDefaultFormState(schema, formData, rootSchema) {
    return (0, utils_1.getDefaultFormState)(validator_ajv6_1.default, schema, formData, rootSchema);
}
/**
 * If you use this with schema data, note that this function doesn't check default data.
 */
function hasData(formData) {
    function hasValue(value) {
        return value !== undefined && value !== null && value !== "";
    }
    if (!hasValue(formData)) {
        return false;
    }
    else {
        if (!Array.isArray(formData))
            formData = [formData];
        return formData.some((data) => {
            if ((0, exports.isObject)(data)) {
                return Object.keys(data).some(_field => propertyHasData(_field, data));
            }
            else
                return hasValue(data);
        });
    }
}
/**
 * If you use this with schema data, note that this function doesn't check default data.
 */
function propertyHasData(field, container) {
    if (!container)
        return false;
    const data = container[field];
    return !!(data &&
        (!(0, exports.isObject)(data) || (Object.keys(data).length > 0 && hasData(data))) &&
        (!Array.isArray(data) || (data.length > 0 && hasData(data))));
}
function getUpdateObjectFromJSONPath(path, injection) {
    console.warn("'getUpdateObjectFromJSONPath' works with JSON pointers, not JSON path! This function is deprecated and will be removed in the future, please use 'getUpdateObjectFromJSONPointer' instead");
    return getUpdateObjectFromJSONPointer(path, injection);
}
function getUpdateObjectFromJSONPointer(path, injection) {
    let update = {};
    let updatePointer = update;
    let lastPathName = "";
    let splittedPath = path.split("/").filter(s => !isEmptyString(s));
    if (!splittedPath.length) {
        return update;
    }
    splittedPath.forEach((pathStep, i) => {
        updatePointer[pathStep] = {};
        if (i < splittedPath.length - 1)
            updatePointer = updatePointer[pathStep];
        lastPathName = pathStep;
    });
    updatePointer[lastPathName] = injection;
    return update;
}
function immutableDelete(_obj, _delProp) {
    const simple = (obj, delProp) => {
        if (!(delProp in obj)) {
            return obj;
        }
        const newObj = {};
        Object.keys(obj).forEach(prop => {
            if (prop !== delProp)
                newObj[prop] = obj[prop];
        });
        return newObj;
    };
    if (_delProp[0] === "/") {
        const splits = _delProp.split("/");
        const last = splits.pop();
        const container = parseJSONPointer(_obj, "/" + splits.join("/"), true);
        if (!container || !(last in container)) {
            return _obj;
        }
        return updateSafelyWithJSONPointer(_obj, simple(container, last), "/" + splits.join("/"));
    }
    else {
        return simple(_obj, _delProp);
    }
}
function getUiOptions(container) {
    if (container) {
        const options = container["ui:options"] || container.options;
        return options ? options : {};
    }
    return {};
}
function getInnerUiSchema(parentUiSchema = {}) {
    let { uiSchema } = parentUiSchema, restOfUiSchema = __rest(parentUiSchema, ["uiSchema"]);
    if (uiSchema
        && ((0, Context_1.default)("VIRTUAL_SCHEMA_NAMES")[uiSchema["ui:field"]]
            || (0, Context_1.default)("SCHEMA_FIELD_WRAPPERS")[uiSchema["ui:field"]]) && parentUiSchema["ui:buttons"]) {
        uiSchema = Object.assign(Object.assign({}, uiSchema), { "ui:buttons": [
                ...(uiSchema["ui:buttons"] || []),
                ...(parentUiSchema["ui:buttons"] || [])
            ] });
    }
    return Object.assign(Object.assign(Object.assign({}, restOfUiSchema), { "ui:field": undefined, "ui:settings": undefined, "ui:options": uiSchema ? undefined : restOfUiSchema["ui:options"], "ui:buttons": uiSchema ? undefined : parentUiSchema["ui:buttons"] }), (uiSchema || {}));
}
function isNullOrUndefined(val) {
    return val === null || val === undefined;
}
function isEmptyString(val) {
    return val === "" || isNullOrUndefined(val);
}
function parseJSONPointer(object, jsonPointer, safeMode, strictEmptyPath = false) {
    if (jsonPointer === "" || jsonPointer === "/") {
        return object;
    }
    let splitPath = String(jsonPointer).split("/");
    if (String(jsonPointer)[0] === "/") {
        splitPath = splitPath.splice(1);
    }
    if (!strictEmptyPath) {
        splitPath = splitPath.filter(s => !isEmptyString(s));
    }
    return splitPath.reduce((o, s, i) => {
        if (safeMode && !o || !(s in o)) {
            if (!o)
                o = {};
            if (safeMode === "createParents") {
                o[s] = {};
            }
            else if (i < splitPath.length - 1) {
                return {};
            }
        }
        return o[s];
    }, object);
}
function getReactComponentName(WrappedComponent) {
    return (WrappedComponent.displayName ||
        WrappedComponent.name ||
        "Component");
}
function isMultiSelect(schema, uiSchema) {
    return (0, utils_1.isMultiSelect)(validator_ajv6_1.default, schema) && !(schema.type === "array" &&
        uiSchema &&
        uiSchema.items &&
        uiSchema.items["ui:field"]);
}
function isSelect(schema) {
    return (0, utils_1.isSelect)(validator_ajv6_1.default, schema);
}
const CHECKBOX_CLASS = "laji-form-checkbox-widget-tab-target";
const IMG_ADD_CLASS = "laji-form-drop-zone";
const tabbableSelectors = [
    "input",
    "select",
    "textarea"
].map(type => `${type}:not([type="hidden"]):not(:disabled):not([readonly]):not([type="file"]):not(.leaflet-control-layers-selector):not(.laji-map-input):not([type="radio"])`);
const tabbableSelectorsQuery = [
    ...tabbableSelectors,
    `.${CHECKBOX_CLASS}`,
    `.${IMG_ADD_CLASS}`
].join(", ");
function getTabbableFields(elem, reverse) {
    const fieldsNodeList = elem.querySelectorAll(tabbableSelectorsQuery);
    let fields = Array.from(fieldsNodeList).filter(node => node.tabIndex !== -1);
    if (reverse)
        fields = fields.reverse();
    return fields;
}
function isTabbableInput(elem) {
    return elem.id.match(/^_laji-form_/)
        || ["input", "select", "textarea"].includes(elem.tagName.toLowerCase())
        || elem.className.includes(CHECKBOX_CLASS)
        || elem.className.includes(IMG_ADD_CLASS);
}
function canFocusNextInput(root, inputElem) {
    const node = (0, react_dom_1.findDOMNode)(root);
    return ((node === null || node === void 0 ? void 0 : node.querySelectorAll) && isTabbableInput(inputElem));
}
function findNearestParentSchemaElem(elem) {
    while (elem && !("id" in elem ? elem.id : "").match(/^_laji-form_/)) {
        elem = elem.parentNode;
    }
    return elem;
}
function findNearestParentTabbableElem(elem) {
    while (!isTabbableInput(elem)) {
        elem = elem.parentNode;
    }
    return elem;
}
const ReactUtils = (context) => ({
    findNearestParentSchemaElemId: exports.findNearestParentSchemaElemId,
    getSchemaElementById: exports.getSchemaElementById,
    focusById: _focusById(context),
    focusAndScroll: _focusAndScroll(context),
    shouldSyncScroll: _shouldSyncScroll(context),
    syncScroll: (0, exports._syncScroll)(context),
    filterItemIdsDeeply: _filterItemIdsDeeply(context),
    formDataIsEmpty: _formDataIsEmpty(context),
    formDataEquals: _formDataEquals(context),
    keyboardClick: _keyboardClick(context),
    getNextInput: (0, exports.getNextInput)(context),
    focusNextInput: (0, exports.focusNextInput)(context),
    getNextInputInInputs: (0, exports.getNextInputInInputs)(context)
});
exports.ReactUtils = ReactUtils;
const getNextInputInInputs = (formContext) => (inputElem, reverseDirection = false, fields) => {
    const formReactNode = formContext.formRef.current;
    const formElem = (0, react_dom_1.findDOMNode)(formReactNode);
    if (!formElem) {
        return undefined;
    }
    if (!document.activeElement) {
        return undefined;
    }
    if (!inputElem)
        inputElem = findNearestParentTabbableElem(document.activeElement);
    if (!inputElem) {
        return undefined;
    }
    if (reverseDirection) {
        fields = fields.reverse();
    }
    if (!canFocusNextInput(formElem, inputElem))
        return undefined;
    let found = false;
    for (let field of fields) {
        if (field === inputElem) {
            found = true;
            continue;
        }
        if (found) {
            // Skip hidden fields.
            if (!field.offsetParent) {
                continue;
            }
            return field;
        }
    }
    return undefined;
};
exports.getNextInputInInputs = getNextInputInInputs;
const getNextInput = (formContext) => (inputElem, reverseDirection = false) => {
    const formElem = (0, react_dom_1.findDOMNode)(formContext.formRef.current);
    const fields = getTabbableFields(formElem);
    const input = formContext.utils.getNextInputInInputs(inputElem, reverseDirection, fields);
    if (!input) {
        // Try to find a "tabbable element" from inside the nearest parent schema element.
        const nearestParentField = findNearestParentSchemaElem(inputElem);
        if (nearestParentField) {
            const nearestTabbableElem = nearestParentField.querySelector(tabbableSelectorsQuery);
            if (nearestTabbableElem) {
                return formContext.utils.getNextInputInInputs(nearestTabbableElem, reverseDirection, fields);
            }
        }
    }
    return input;
};
exports.getNextInput = getNextInput;
const focusNextInput = (formContext) => (reverseDirection = false) => {
    const formReactNode = formContext.formRef.current;
    if (!formReactNode) {
        throw new Error("focusNextInput() didn't find form ref");
    }
    const { uiSchema = {} } = formReactNode.props;
    if (uiSchema.autoFocus === false) {
        return false;
    }
    const field = formContext.utils.getNextInput(document.activeElement, reverseDirection);
    if (field) {
        field.focus();
        scrollIntoViewIfNeeded(field, formContext.topOffset, formContext.bottomOffset);
        return true;
    }
    return false;
};
exports.focusNextInput = focusNextInput;
const findNearestParentSchemaElemId = (elem) => {
    const nearestParentSchemaElem = findNearestParentSchemaElem(elem) || document.getElementById("_laji-form_root");
    return nearestParentSchemaElem ? nearestParentSchemaElem.id.replace("_laji-form_", "") : undefined;
};
exports.findNearestParentSchemaElemId = findNearestParentSchemaElemId;
const getSchemaElementById = (id) => {
    return document.getElementById(`_laji-form_${id}`);
};
exports.getSchemaElementById = getSchemaElementById;
const _focusById = (context) => (id, focus = true) => {
    const elem = (0, exports.getSchemaElementById)(id);
    if (elem && document.body.contains(elem)) {
        const tabbableFields = getTabbableFields(elem);
        if (tabbableFields && tabbableFields.length) {
            focus && tabbableFields[0].focus();
            scrollIntoViewIfNeeded(elem, context.topOffset, context.bottomOffset);
            const rootContext = (0, Context_1.default)(context.contextId);
            rootContext.lastIdToFocus = id; // Mark for components that manipulate scroll positions
            rootContext.windowScrolled = getWindowScrolled();
            return true;
        }
    }
    return false;
};
const focusById = (context, id, focus) => _focusById(context)(id, focus);
exports.focusById = focusById;
const _focusAndScroll = (context) => (idToFocus, idToScroll, focus = true) => {
    const { contextId, topOffset, bottomOffset } = context;
    const _context = (0, Context_1.default)(contextId);
    if (idToFocus === undefined && idToScroll === undefined)
        return;
    if (idToFocus && !context.utils.focusById(getKeyHandlerTargetId(idToFocus, _context), focus))
        return false;
    if (idToScroll) {
        const elemToScroll = document.getElementById(getKeyHandlerTargetId(idToScroll, _context));
        const elemToFocus = (0, exports.getSchemaElementById)(getKeyHandlerTargetId(idToFocus, _context));
        if (!elemToScroll || !elemToFocus) {
            return end();
        }
        const wouldScrollTo = getScrollPositionForScrollIntoViewIfNeeded(elemToScroll, topOffset, bottomOffset);
        const scrollAmount = wouldScrollTo - getWindowScrolled();
        const { top } = elemToFocus.getBoundingClientRect();
        const viewTopDistanceFromTop = top - scrollAmount;
        // Don't scroll if scrolling would hide focused elem top.
        if (viewTopDistanceFromTop < topOffset) {
            return end();
        }
        else {
            scrollIntoViewIfNeeded(elemToScroll, topOffset, bottomOffset);
        }
    }
    return end();
    function end() {
        _context.lastIdToScroll = idToScroll;
        _context.lastIdToFocus = idToFocus;
        _context.windowScrolled = getWindowScrolled();
        return true;
    }
};
const focusAndScroll = (context, idToFocus, idToScroll, focus) => _focusAndScroll(context)(idToFocus, idToScroll, focus);
exports.focusAndScroll = focusAndScroll;
const _shouldSyncScroll = (context) => () => {
    return (0, Context_1.default)(context.contextId).windowScrolled === getWindowScrolled();
};
const shouldSyncScroll = (context) => _shouldSyncScroll(context)();
exports.shouldSyncScroll = shouldSyncScroll;
const _syncScroll = (context) => (force = false) => {
    if (force || (0, exports.shouldSyncScroll)(context)) {
        const { lastIdToFocus, lastIdToScroll } = (0, Context_1.default)(context.contextId);
        (0, exports.focusAndScroll)(context, lastIdToFocus, lastIdToScroll, false);
    }
};
exports._syncScroll = _syncScroll;
const syncScroll = (context, force) => (0, exports._syncScroll)(context)(force);
exports.syncScroll = syncScroll;
const filterLajiFormId = (item) => {
    if (item && item._lajiFormId) {
        const { _lajiFormId } = item, _item = __rest(item, ["_lajiFormId"]);
        item = _item;
    }
    return item;
};
exports.filterLajiFormId = filterLajiFormId;
const filterItemId = (item) => {
    if (item && (item._lajiFormId || item.id)) {
        const { _lajiFormId, id } = item, _item = __rest(item, ["_lajiFormId", "id"]);
        item = _item;
    }
    return item;
};
exports.filterItemId = filterItemId;
const _filterItemIdsDeeply = (context) => (item, idSchemaId) => {
    const tmpIdTree = context.services.ids.getRelativeTmpIdTree(idSchemaId);
    let [_item] = walkFormDataWithIdTree(item, tmpIdTree, exports.filterItemId);
    return _item;
};
const filterItemIdsDeeply = (item, context, idSchemaId) => _filterItemIdsDeeply(context)(item, idSchemaId);
exports.filterItemIdsDeeply = filterItemIdsDeeply;
const _formDataIsEmpty = (context) => (props) => {
    const tmpIdTree = context.services.ids.getRelativeTmpIdTree(props.idSchema.$id);
    let [item] = walkFormDataWithIdTree(props.formData, tmpIdTree, exports.filterItemId);
    return deepEquals(item, getDefaultFormState(props.schema, undefined, props.registry.rootSchema));
};
const formDataIsEmpty = (props, context) => _formDataIsEmpty(context)(props);
exports.formDataIsEmpty = formDataIsEmpty;
const _formDataEquals = (context) => (f1, f2, id) => {
    const tmpIdTree = context.services.ids.getRelativeTmpIdTree(id);
    const [_f1, _f2] = [f1, f2].map(i => walkFormDataWithIdTree(i, tmpIdTree, exports.filterItemId)[0]);
    return deepEquals(_f1, _f2);
};
const formDataEquals = (f1, f2, context, id) => {
    return _formDataEquals(context)(f1, f2, id);
};
exports.formDataEquals = formDataEquals;
const _keyboardClick = ({ contextId }) => (fn, keys = [" ", "Enter"]) => {
    return (e) => {
        var _a, _b;
        if ((_b = (_a = e.target) === null || _a === void 0 ? void 0 : _a.matches) === null || _b === void 0 ? void 0 : _b.call(_a, tabbableSelectorsQuery)) {
            const { shortcuts } = (0, Context_1.default)(contextId);
            keys = keys.filter(k => !(shortcuts === null || shortcuts === void 0 ? void 0 : shortcuts[k]));
        }
        if (e.altKey || e.ctrlKey || keys.every(k => e.key !== k)) {
            return;
        }
        e.preventDefault();
        e.stopPropagation();
        fn(e);
    };
};
const keyboardClick = (fn, context) => {
    return _keyboardClick(context)(fn);
};
exports.keyboardClick = keyboardClick;
function getNestedTailUiSchema(uiSchema) {
    while (uiSchema && uiSchema.uiSchema) {
        uiSchema = uiSchema.uiSchema;
    }
    return uiSchema;
}
function updateTailUiSchema(uiSchema, updateObject) {
    let tailPointer = {};
    let root = tailPointer;
    let uiSchemaPointer = uiSchema;
    while (uiSchemaPointer.uiSchema) {
        uiSchemaPointer = uiSchemaPointer.uiSchema;
        tailPointer.uiSchema = {};
        if (uiSchemaPointer.uiSchema)
            tailPointer = tailPointer.uiSchema;
    }
    tailPointer.uiSchema = updateObject;
    return (0, immutability_helper_1.default)(uiSchema, root);
}
function getNestedUiFieldsList(uiSchema) {
    const list = [];
    while (uiSchema.uiSchema && uiSchema.uiSchema["ui:field"]) {
        list.push(uiSchema.uiSchema["ui:field"]);
        uiSchema = uiSchema.uiSchema;
    }
    return list;
}
function getBootstrapCols(width) {
    return ["lg", "md", "sm", "xs"].reduce((o, c) => {
        o[c] = width;
        return o;
    }, {});
}
function isDescendant(parent, child) {
    let node = child.parentNode;
    while (node != null) {
        if (node == parent) {
            return true;
        }
        node = node.parentNode;
    }
    return false;
}
function getKeyHandlerTargetId(target = "", context, formData) {
    var _a;
    while (target.match(/%\{([^{}]*)\}/)) {
        const path = ((_a = /%\{([^{}]*)\}/.exec(target)) === null || _a === void 0 ? void 0 : _a[1]) || "";
        if (!path.startsWith("context") && !path.startsWith("formData"))
            throw Error("Should evaluate 'context' or 'formData'");
        target = target.replace(`%{${path}}`, eval(path));
    }
    return target;
}
function capitalizeFirstLetter(string) {
    return string.charAt(0).toUpperCase() + string.slice(1);
}
function decapitalizeFirstLetter(string) {
    return string.charAt(0).toLowerCase() + string.slice(1);
}
function stringifyKeyCombo(keyCombo = "") {
    return keyCombo.split("+").map(key => {
        if (key === " ")
            key = "space";
        return capitalizeFirstLetter(key);
    }).join(" + ");
}
function canAdd(props) {
    return (!("canAdd" in props) || props.canAdd) && getUiOptions(props.uiSchema).canAdd !== false;
}
function bsSizeToPixels(bsSize) {
    switch (bsSize) {
        case "lg":
            return 1200;
        case "md":
            return 992;
        case "sm":
            return 768;
        case "xs":
            return 576;
        default:
            throw new Error(`Unknown bootstrap size ${bsSize}. Should be one of 'lg', 'md', 'sm' or 'xs'`);
    }
}
function pixelsToBsSize(pixels) {
    if (pixels < 576) {
        return "xs";
    }
    else if (pixels < 768) {
        return "sm";
    }
    else if (pixels < 992) {
        return "md";
    }
    else if (pixels < 1200) {
        return "lg";
    }
    return "";
}
function applyFunction(props) {
    let { "ui:functions": functions, "ui:childFunctions": childFunctions } = (props.uiSchema || {});
    const asArrayIfDefined = (item) => item ? asArray(item) : [];
    if (childFunctions) {
        functions = [
            { "ui:field": "UiFieldMapperArrayField", "ui:options": { functions: asArrayIfDefined(childFunctions) } },
            ...asArrayIfDefined(functions)
        ];
    }
    if (!functions)
        return props;
    const computedProps = ((Array.isArray(functions)) ? functions : [functions]).reduce((_props, { "ui:field": uiField, "ui:options": uiOptions }) => {
        _props = Object.assign(Object.assign({}, _props), { uiSchema: Object.assign(Object.assign({}, _props.uiSchema), { "ui:field": uiField, "ui:options": uiOptions, uiSchema: undefined }) });
        const { state = {} } = new props.registry.fields[uiField](_props);
        return Object.assign(Object.assign({}, _props), state);
    }, Object.assign(Object.assign({}, props), { formContext: props.registry.formContext }));
    return Object.assign(Object.assign({}, computedProps), { uiSchema: Object.assign(Object.assign({}, computedProps.uiSchema), { "ui:functions": undefined, "ui:childFunctions": undefined, "ui:field": props.uiSchema["ui:field"], "ui:options": props.uiSchema["ui:options"], uiSchema: props.uiSchema.uiSchema }) });
}
function getWindowScrolled() {
    return window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
}
function getScrollPositionForScrollIntoViewIfNeeded(elem, topOffset = 0, bottomOffset = 0) {
    if (!elem)
        return getWindowScrolled();
    const rect = elem.getBoundingClientRect();
    const html = document.documentElement;
    const inView = (rect.top >= topOffset &&
        rect.bottom <= (window.innerHeight || html.clientHeight) - bottomOffset);
    const elemTopDistFromViewportTop = rect.top;
    const pageScrolled = getWindowScrolled();
    if (inView)
        return pageScrolled;
    return pageScrolled + elemTopDistFromViewportTop - topOffset;
}
function scrollIntoViewIfNeeded(elem, topOffset = 0, bottomOffset = 0) {
    window.scrollTo(0, getScrollPositionForScrollIntoViewIfNeeded(elem, topOffset, bottomOffset));
}
function filter(properties, filter, filterType = "blacklist", getValue) {
    const filterDictionary = {};
    filter.forEach(_enum => { filterDictionary[_enum] = true; });
    const filterFn = (item) => {
        const value = getValue ? getValue(item) : item;
        return filterDictionary[value];
    };
    return properties.filter(filterType === "whitelist" ? filterFn : e => !filterFn(e));
}
function updateSafelyWithJSONPath(obj, value, path, immutably, createNew) {
    console.warn("'updateSafelyWithJSONPath' works with JSON pointers, not JSON path! This function is deprecated and will be removed in the future, please use 'updateSafelyWithJSONPointer' instead");
    return updateSafelyWithJSONPointer(obj, value, path, immutably, createNew);
}
function updateSafelyWithJSONPointer(obj, value, path, immutably = true, createNew = () => ({})) {
    if (path === "/") {
        return value;
    }
    if (!immutably) {
        const splitted = path.split("/").filter(s => !isEmptyString(s));
        splitted.reduce((o, split, i) => {
            if (i === splitted.length - 1) {
                o[split] = value;
                return;
            }
            if (!o[split]) {
                o[split] = createNew(o, split);
            }
            return o[split];
        }, obj);
        return obj;
    }
    let injectionTarget = false;
    try {
        injectionTarget = parseJSONPointer(obj, path);
    }
    catch (e) {
        injectionTarget = makePath(injectionTarget);
    }
    // If path for injection doesn't exist, we create it immutably.
    if (!injectionTarget) {
        injectionTarget = makePath(injectionTarget);
    }
    const updateObject = getUpdateObjectFromJSONPointer(path, { $set: value });
    return (0, immutability_helper_1.default)(obj, updateObject);
    function makePath(injectionTarget) {
        const splitPath = path.split("/").filter(s => !isEmptyString(s));
        let _splitPath = "";
        splitPath.reduce((o, split) => {
            _splitPath += `/${split}`;
            if (!o[split]) {
                obj = (0, immutability_helper_1.default)(obj, getUpdateObjectFromJSONPointer(_splitPath, { $set: createNew(obj, _splitPath, o, split) }));
            }
            const next = parseJSONPointer(obj, _splitPath);
            injectionTarget = next;
            return next;
        }, obj);
        return injectionTarget;
    }
}
function injectButtons(uiSchema, buttons, buttonsPath) {
    const existingButtons = parseJSONPointer(uiSchema, `${buttonsPath}/ui:options/buttons`);
    return updateSafelyWithJSONPointer(uiSchema, existingButtons ? [...existingButtons, ...buttons] : buttons, `${buttonsPath}/ui:options/buttons`);
}
function dictionarify(array, getKey, getValue) {
    return array.reduce((o, k) => {
        o[getKey ? getKey(k) : k] = getValue ? getValue(k) : true;
        return o;
    }, {});
}
const tableFormatters = {
    unknownTaxon: (item, formatted, options, parentProps = {}) => (isEmptyString(item) || (parentProps.formData || {})[options.idField])
        ? formatted
        : (React.createElement(ReactContext_1.default.Consumer, null, ({ theme: { Glyphicon } }) => React.createElement("span", null,
            formatted,
            " ",
            React.createElement("span", { className: "text-warning" },
                React.createElement(Glyphicon, { glyph: "warning-sign" })))))
};
function formatValue(props, _formatter, parentProps) {
    let { formData, uiSchema = {}, schema, registry } = props;
    let formatter = undefined;
    let formatterComponent = undefined;
    if (uiSchema["ui:widget"])
        formatterComponent = registry.widgets[uiSchema["ui:widget"]];
    else if (schema.type === "boolean")
        formatterComponent = registry.widgets.CheckboxWidget;
    else if (uiSchema["ui:field"])
        formatterComponent = registry.fields[uiSchema["ui:field"]];
    if (formatterComponent && formatterComponent.prototype && formatterComponent.prototype.formatValue) {
        formatter = formatterComponent.prototype.formatValue;
    }
    else if (formatterComponent && formatterComponent.prototype && formatterComponent.prototype.__proto__ && formatterComponent.prototype.__proto__.formatValue) {
        formatter = formatterComponent.prototype.__proto__.formatValue;
    }
    const arrayJoiner = (value, i, length, separator = "; ") => {
        const comma = React.createElement(React.Fragment, { key: `_${i}` }, separator);
        return i < length - 1
            ? [value, comma] : [value];
    };
    let formatted = formData;
    if (formatter) {
        formatted = formatter(formData, getUiOptions(uiSchema), props, parentProps);
    }
    else if (isEmptyString(formData)) {
        formatted = "";
    }
    else if (isMultiSelect(schema)) {
        formatted = formData.filter((s) => s !== undefined).map((_val) => schema.items.oneOf.find((one) => one.const === _val).title).join(", ");
    }
    else if (schema.type === "object") {
        const keys = Object.keys(formData);
        return keys.map((_col, i) => {
            const child = React.createElement(React.Fragment, { key: _col }, formatValue(Object.assign(Object.assign({}, props), { schema: schema.properties[_col], uiSchema: uiSchema[_col], formData: formData[_col] })));
            return arrayJoiner(child, i, keys.length);
        });
    }
    else if (schema.type === "array") {
        formatted = React.createElement("span", { className: "single-active-array-table-array" }, formData.map((_val, i) => {
            const child = React.createElement(React.Fragment, { key: i }, formatValue(Object.assign(Object.assign({}, props), { schema: props.schema.items, uiSchema: uiSchema.items, formData: _val })));
            return arrayJoiner(child, i, formData.length, "; ");
        }));
    }
    else if (isSelect(schema)) {
        formatted = isEmptyString(formData) ? formData : schema.oneOf.find((one) => one.const === formData).title;
    }
    else if (schema.type === "boolean") {
        formatted = props.formContext.translations[formData ? "yes" : "no"];
    }
    if (_formatter) {
        formatted = tableFormatters[_formatter.formatter](formData, formatted, _formatter, parentProps);
    }
    return formatted;
}
const formatErrorMessage = (msg) => msg.replace(/^\[.*\]/, "");
exports.formatErrorMessage = formatErrorMessage;
function checkRules(rules, props, cache, prop = "formData") {
    const passes = (Array.isArray(rules) ? rules : [rules]).every((rule, idx) => {
        let passes;
        // BW compatibility for old string  rule
        if (["isAdmin", "isLoggedIn", "isEdit", "isReadonly"].includes(rule)) {
            rule = { rule };
        }
        const { field, regexp, valueIn, valueIncludes, valueLengthLessThan, rule: _rule } = rule;
        if (_rule) {
            if (_rule === "isAdmin") {
                passes = props.formContext.uiSchemaContext.isAdmin;
            }
            else if (_rule === "isLoggedIn") {
                passes = props.formContext.uiSchemaContext.creator;
            }
            else if (_rule === "isEdit") {
                passes = props.formContext.uiSchemaContext.isEdit;
            }
            else if (_rule === "isReadonly") {
                passes = props.readonly;
            }
        }
        else {
            let value = parseJSONPointer(props[rule.prop || prop] || {}, field);
            if (value === undefined)
                value = "";
            if (regexp) {
                passes = `${value}`.match(new RegExp(regexp));
            }
            else if (valueIn) {
                if (cache) {
                    if (!cache[idx]) {
                        cache[idx] = dictionarify(valueIn);
                    }
                    passes = cache[idx][value];
                }
                else {
                    passes = dictionarify(valueIn)[value];
                }
            }
            else if (valueIncludes !== undefined) {
                passes = value.includes(valueIncludes);
            }
            else if (valueLengthLessThan !== undefined) {
                passes = value.length < valueLengthLessThan;
            }
        }
        return rule.complement ? !passes : passes;
    });
    return cache ? { passes, cache } : passes;
}
function checkArrayRules(rules, props, idx, cache, prop = "formData") {
    const arrayRules = (Array.isArray(rules) ? rules : [rules]).filter(rule => ["isLast", "idx"].some(r => r in rule));
    const passes = arrayRules.every(rule => {
        let passes;
        if ("isLast" in rule) {
            passes = (idx === props.formData.length - 1) === rule.isLast;
        }
        else if ("idx" in rule) {
            passes = idx === rule.idx;
        }
        if (passes !== undefined) {
            return rule.complement ? !passes : passes;
        }
        return true;
    });
    const nonArrayRules = (Array.isArray(rules) ? rules : [rules]).filter(rule => !arrayRules.includes(rule));
    if (nonArrayRules.length) {
        const nonArrayRulesCheck = checkRules(nonArrayRules, Object.assign(Object.assign({}, props), { formData: props.formData[idx] }), cache, prop);
        const allPass = passes && cache ? nonArrayRulesCheck.passes : nonArrayRulesCheck;
        if (cache) {
            return { passes: allPass, cache };
        }
        else {
            return allPass;
        }
    }
    else {
        return cache ? { cache, passes } : passes;
    }
}
function bringRemoteFormData(formData, formContext) {
    if (formContext.formDataTransformers) {
        return formContext.formDataTransformers.reduce((formData, { "ui:field": uiField, props: fieldProps }) => {
            const { state = {} } = new fieldProps.registry.fields[uiField](Object.assign(Object.assign({}, fieldProps), { formData }));
            return state.formData;
        }, formData);
    }
    else {
        return formData;
    }
}
function triggerParentComponent(eventName, e, props) {
    if (props && props[eventName]) {
        e.persist && e.persist();
        props[eventName](e);
    }
}
function parseSchemaFromFormDataPointer(schema, pointer) {
    const splits = pointer.split("/").filter(s => !isEmptyString(s));
    const value = splits.reduce((o, s) => {
        if (!isNaN(parseInt(s))) {
            return o.items;
        }
        if (o.type === "array" && o.items.properties[s])
            return o.items.properties[s];
        if (o.type === "array")
            return o.items;
        return o.properties[s];
    }, schema);
    return value;
}
function parseUiSchemaFromFormDataPointer(uiSchema, pointer) {
    const splits = pointer.split("/").filter(s => !isEmptyString(s));
    return splits.reduce((o, s) => {
        if (!isNaN(parseInt(s))) {
            return o.items;
        }
        if (o && o.items)
            return o.items[s];
        return o ? o[s] : {};
    }, uiSchema);
}
function checkJSONPointer(obj, pointer) {
    if (!obj)
        return false;
    const splits = pointer.split("/").filter(s => !isEmptyString(s));
    try {
        let _pointer = obj;
        return splits.every(split => {
            const exists = split in _pointer;
            _pointer = _pointer[split];
            return exists;
        });
    }
    catch (e) {
        return false;
    }
}
const JSONPointerToId = (fieldName) => fieldName[0] === "/" ? fieldName.replace(/(?!^)\//g, "_").substr(1) : fieldName;
exports.JSONPointerToId = JSONPointerToId;
const idSchemaIdToJSONPointer = (id) => id.replace(/root_|_/g, "/");
exports.idSchemaIdToJSONPointer = idSchemaIdToJSONPointer;
function schemaJSONPointer(schema, JSONPointer) {
    if (JSONPointer[0] !== "/") {
        JSONPointer = `/${JSONPointer}`;
    }
    let schemaPointer = schema;
    return JSONPointer.split("/").filter(s => !isEmptyString(s)).reduce((path, s) => {
        if (schemaPointer[s]) {
            schemaPointer = schemaPointer[s];
            return `${path}/${s}`;
        }
        else if (!isNaN(+s) && schemaPointer.items) {
            schemaPointer = schemaPointer.items;
            return `${path}/items`;
        }
        else if (schemaPointer.properties && schemaPointer.properties[s]) {
            schemaPointer = schemaPointer.properties[s];
            return `${path}/properties/${s}`;
        }
        return undefined;
    }, "");
}
function uiSchemaJSONPointer(schema, JSONPointer) {
    if (JSONPointer[0] !== "/")
        return JSONPointer;
    let schemaPointer = schema;
    return JSONPointer.split("/").filter(s => !isEmptyString(s)).reduce((path, s) => {
        if (schemaPointer[s]) {
            schemaPointer = schemaPointer[s];
            return `${path}/${s}`;
        }
        else if (schemaPointer.properties && schemaPointer.properties[s]) {
            schemaPointer = schemaPointer.properties[s];
            return `${path}/${s}`;
        }
        else if (schemaPointer.items.properties && schemaPointer.items.properties[s]) {
            schemaPointer = schemaPointer.items.properties[s];
            return `${path}/items/${s}`;
        }
        else if (!isNaN(+s) && schemaPointer.items) {
            schemaPointer = schemaPointer.items;
            return `${path}/items`;
        }
        return undefined;
    }, "");
}
function updateFormDataWithJSONPointer(schemaProps, value, path) {
    if (path === "/") {
        return value;
    }
    return updateSafelyWithJSONPointer(schemaProps.formData, value, path, true, (__formData, _path) => {
        const schemaPointer = schemaJSONPointer(schemaProps.schema, _path);
        if (schemaPointer === undefined) {
            throw new Error(`Bad JSON Schema pointer '${schemaPointer}!`);
        }
        const _schema = parseJSONPointer(schemaProps.schema, schemaPointer);
        let _default = getDefaultFormState(_schema, undefined, schemaProps.registry.rootSchema);
        if (!_default && _schema.type === "array") {
            return [];
        }
        return _default;
    });
}
let uuid = 0;
const assignUUID = (item, immutably = false) => {
    if ((0, exports.isObject)(item) && !item.id && !item._lajiFormId) {
        uuid++;
        if (immutably) {
            return Object.assign(Object.assign({}, item), { _lajiFormId: uuid });
        }
        else {
            item._lajiFormId = uuid;
            return item;
        }
    }
    return item;
};
exports.assignUUID = assignUUID;
const getUUID = (item) => item ? (item.id || item._lajiFormId) : undefined;
exports.getUUID = getUUID;
/**
 * Return item UUID or the parent UUID
 **/
const getFieldUUID = (props) => (0, exports.getUUID)(props.formData) || props.formContext._parentLajiFormId || "root";
exports.getFieldUUID = getFieldUUID;
function walkFormDataWithIdTree(_formData, tree, itemOperator) {
    const ids = {};
    const walk = (_formData, tree) => {
        if (!tree)
            return _formData;
        const { _hasId } = tree, _tree = __rest(tree, ["_hasId"]);
        if (_hasId && (0, exports.isObject)(_formData)) {
            _formData = itemOperator ? itemOperator(_formData) : _formData;
        }
        if (Object.keys(_tree).length && (0, exports.isObject)(_formData)) {
            return Object.keys(_formData).reduce((f, k) => {
                if (tree[k]) {
                    f[k] = walk(_formData[k], tree[k]);
                }
                else {
                    f[k] = _formData[k];
                }
                return f;
            }, {});
        }
        else if (tree && Array.isArray(_formData)) {
            return _formData.map(item => {
                item = walk(item, tree);
                item = itemOperator ? itemOperator(item) : item;
                const uuid = (0, exports.getUUID)(item);
                if (uuid) {
                    ids[uuid] = true;
                }
                return item;
            });
        }
        return _formData;
    };
    const formData = walk(_formData, tree);
    return [formData, ids];
}
function addLajiFormIds(_formData, tree, immutably = true) {
    const itemOperator = (item) => (0, exports.assignUUID)(item, immutably);
    return walkFormDataWithIdTree(_formData, tree, itemOperator);
}
function getAllLajiFormIdsDeeply(_formData, tree) {
    return walkFormDataWithIdTree(_formData, tree)[1];
}
function removeLajiFormIds(formData, tree) {
    const itemOperator = (item) => immutableDelete(item, "_lajiFormId");
    return walkFormDataWithIdTree(formData, tree, itemOperator)[0];
}
function findPointerForLajiFormId(tmpIdTree = {}, formData, lajiFormId) {
    if (tmpIdTree._hasId) {
        if (Array.isArray(formData)) {
            for (let idx in (formData || [])) {
                const item = formData[idx];
                if ((0, exports.getUUID)(item) === lajiFormId) {
                    return "/" + idx;
                }
            }
        }
        else if (formData && (0, exports.getUUID)(formData) === lajiFormId) {
            return "";
        }
    }
    for (const k of Object.keys(tmpIdTree)) {
        if ((0, exports.isObject)(formData[k])) {
            const find = findPointerForLajiFormId(tmpIdTree[k], formData[k], lajiFormId);
            if (find !== undefined || find === "") {
                return `/${k}${find}`;
            }
        }
        else if (Array.isArray(formData[k])) {
            for (const i in formData[k]) {
                const item = formData[k][i];
                const find = findPointerForLajiFormId(tmpIdTree[k], item, lajiFormId);
                if (find !== undefined || find === "") {
                    return `/${k}/${i}${find}`;
                }
            }
        }
    }
    return undefined;
}
function highlightElem(elem) {
    if (!elem)
        return;
    if (elem.className.includes(" highlight-error-fire"))
        elem.className = elem.className.replace(" highlight-error-fire", "");
    window.setTimeout(() => elem.className = `${elem.className} highlight-error-fire`);
}
function filteredErrors(errorSchema) {
    return Object.keys(errorSchema).reduce((_errorSchema, prop) => {
        if (prop === "__errors") {
            if (errorSchema.__errors.length) {
                _errorSchema.__errors = errorSchema.__errors;
            }
            return _errorSchema;
        }
        const errors = filteredErrors(errorSchema[prop]);
        if (Object.keys(errors).length) {
            _errorSchema[prop] = errors;
        }
        return _errorSchema;
    }, {});
}
function constructTranslations(translations) {
    let dictionaries = { fi: {}, en: {}, sv: {} };
    for (let word in translations) {
        for (let lang in translations[word]) {
            const translation = translations[word][lang];
            dictionaries[lang][word] = decapitalizeFirstLetter(translation);
            dictionaries[lang][capitalizeFirstLetter(word)] = capitalizeFirstLetter(translation);
        }
    }
    return dictionaries;
}
function getIdxWithOffset(idx, offsets, totalOffset) {
    let offset = idx in (offsets || {})
        ? (offsets || {})[idx]
        : totalOffset;
    return (offset || 0) + idx;
}
function getIdxWithoutOffset(idx, offsets, totalOffset) {
    let offset = `_${idx}` in (offsets || {})
        ? (offsets || {})[`_${idx}`]
        : totalOffset;
    return idx - (offset || 0);
}
/**
 * The indices of the formData that a component receives doesn't match the actual root formData indices,
 * if the data is sorted or has offsets. This returns the original index.
 */
function getFormDataIndex(idx, uiSchema) {
    var _a;
    const { idxMap = {}, idxOffsets, totalOffset } = getUiOptions(uiSchema);
    const mappedIdx = (_a = idxMap[idx]) !== null && _a !== void 0 ? _a : idx;
    return getIdxWithOffset(mappedIdx, idxOffsets, totalOffset);
}
/**
 * Given an index pointing to actual index in root formData, returns the index with sorting & offset applied.
 */
function getReversedFormDataIndex(idx, uiSchema) {
    var _a;
    const { idxMap = {}, idxOffsets, totalOffset } = getUiOptions(uiSchema);
    const mappedIdx = (_a = idxMap["_" + idx]) !== null && _a !== void 0 ? _a : idx;
    return getIdxWithoutOffset(mappedIdx, idxOffsets, totalOffset);
}
function toJSONPointer(s) {
    return s[0] !== "/"
        ? "/" + s
        : s;
}
function getTitle(props, idx) {
    var _a, _b, _c, _d;
    let title = (_d = (_b = (_a = props.uiSchema) === null || _a === void 0 ? void 0 : _a["ui:title"]) !== null && _b !== void 0 ? _b : (_c = props.schema) === null || _c === void 0 ? void 0 : _c.title) !== null && _d !== void 0 ? _d : props.name;
    if (!(title === null || title === void 0 ? void 0 : title.includes("%{"))) {
        return title;
    }
    const formatters = {
        idx: typeof idx === "number" ? idx + 1 : undefined,
        title
    };
    return Object.keys(formatters).reduce((_title, key) => {
        [key, capitalizeFirstLetter(key)].map(key => `%{${key}}`).forEach(replacePattern => {
            while (_title.includes(replacePattern)) {
                const fn = replacePattern[2] === replacePattern[2].toLowerCase() ?
                    decapitalizeFirstLetter : capitalizeFirstLetter;
                _title = _title.replace(replacePattern, fn(`${formatters[key]}`));
            }
        });
        return _title;
    }, title);
}
const classNames = (...cs) => cs.filter(s => typeof s === "string").join(" ");
exports.classNames = classNames;
function translate(translations, key, params) {
    return Object.keys(params || {}).reduce((translated, param) => translated.replace(new RegExp(`%{${param}}`, "g"), (params === null || params === void 0 ? void 0 : params[param]) || ""), translations[key]);
}
/**
 * @param value the default value of the setter
 * @returns [stateValue, setTrue, setFalse]
 */
function useBooleanSetter(value) {
    const [open, setOpen] = React.useState(value);
    const setTrue = React.useCallback(() => setOpen(true), []);
    const setFalse = React.useCallback(() => setOpen(false), []);
    return [open, setTrue, setFalse];
}
function usePrevious(value) {
    const ref = React.useRef();
    React.useEffect(() => {
        ref.current = value;
    });
    return ref.current;
}
function asArray(maybeArr) {
    return Array.isArray(maybeArr) ? maybeArr : [maybeArr];
}
function getLajiUri(lajiId) {
    const defaultDomain = "http://tun.fi/";
    const domainMap = {
        "luomus:": "http://id.luomus.fi/",
        "zmuo:": "http://id.zmuo.oulu.fi/",
        "herbo:": "http://id.herb.oulu.fi/",
        "utu:": "http://mus.utu.fi/",
        "gbif-dataset:": "https://www.gbif.org/dataset/",
    };
    if (lajiId.includes(":")) {
        Object.keys(domainMap).forEach(key => {
            lajiId = lajiId.replace(key, domainMap[key]);
        });
    }
    if (lajiId.indexOf("http") === 0)
        return lajiId;
    return defaultDomain + lajiId;
}
