react-checkbox-tree
Version:
A simple and elegant checkbox tree for React.
1,430 lines (1,343 loc) • 139 kB
JavaScript
/*!
* react-checkbox-tree - v2.0.0
* Copyright (c) Jake Zatecky
* Licensed under the MIT License.
*/
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory(require("react"));
else if(typeof define === 'function' && define.amd)
define("ReactCheckboxTree", ["react"], factory);
else if(typeof exports === 'object')
exports["ReactCheckboxTree"] = factory(require("react"));
else
root["ReactCheckboxTree"] = factory(root["react"]);
})(this, function(__WEBPACK_EXTERNAL_MODULE__15__) {
return /******/ (function() { // webpackBootstrap
/******/ var __webpack_modules__ = ([
/* 0 */,
/* 1 */
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var classnames__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
/* harmony import */ var classnames__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(classnames__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var fast_equals__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3);
/* harmony import */ var lodash_memoize__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(4);
/* harmony import */ var lodash_memoize__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(lodash_memoize__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var prop_types__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(5);
/* harmony import */ var prop_types__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(prop_types__WEBPACK_IMPORTED_MODULE_3__);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(15);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_4__);
/* harmony import */ var _js_components_GlobalActions_jsx__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(16);
/* harmony import */ var _js_components_HiddenInput_jsx__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(19);
/* harmony import */ var _js_components_TreeNode_jsx__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(21);
/* harmony import */ var _js_lang_default_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(26);
/* harmony import */ var _js_shapes_iconsShape_js__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(27);
/* harmony import */ var _js_shapes_languageShape_js__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(28);
/* harmony import */ var _js_shapes_listShape_js__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(20);
/* harmony import */ var _js_shapes_nodeShape_js__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(29);
/* harmony import */ var _js_constants_js__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(22);
/* harmony import */ var _js_contexts_js__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(17);
/* harmony import */ var _js_NodeModel_js__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(30);
const combineMemoized = lodash_memoize__WEBPACK_IMPORTED_MODULE_2___default()((newValue, defaultValue) => ({
...defaultValue,
...newValue
}));
const defaultIcons = {
check: /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_4___default().createElement("span", {
className: "rct-icon rct-icon-check"
}),
uncheck: /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_4___default().createElement("span", {
className: "rct-icon rct-icon-uncheck"
}),
halfCheck: /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_4___default().createElement("span", {
className: "rct-icon rct-icon-half-check"
}),
expandClose: /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_4___default().createElement("span", {
className: "rct-icon rct-icon-expand-close"
}),
expandOpen: /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_4___default().createElement("span", {
className: "rct-icon rct-icon-expand-open"
}),
expandAll: /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_4___default().createElement("span", {
className: "rct-icon rct-icon-expand-all"
}),
collapseAll: /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_4___default().createElement("span", {
className: "rct-icon rct-icon-collapse-all"
}),
parentClose: /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_4___default().createElement("span", {
className: "rct-icon rct-icon-parent-close"
}),
parentOpen: /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_4___default().createElement("span", {
className: "rct-icon rct-icon-parent-open"
}),
leaf: /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_4___default().createElement("span", {
className: "rct-icon rct-icon-leaf"
})
};
class CheckboxTree extends (react__WEBPACK_IMPORTED_MODULE_4___default().Component) {
static propTypes = {
nodes: prop_types__WEBPACK_IMPORTED_MODULE_3___default().arrayOf(_js_shapes_nodeShape_js__WEBPACK_IMPORTED_MODULE_12__["default"]).isRequired,
checkKeys: prop_types__WEBPACK_IMPORTED_MODULE_3___default().arrayOf((prop_types__WEBPACK_IMPORTED_MODULE_3___default().string)),
checkModel: prop_types__WEBPACK_IMPORTED_MODULE_3___default().oneOf([_js_constants_js__WEBPACK_IMPORTED_MODULE_13__.CHECK_MODEL.LEAF, _js_constants_js__WEBPACK_IMPORTED_MODULE_13__.CHECK_MODEL.ALL]),
checked: _js_shapes_listShape_js__WEBPACK_IMPORTED_MODULE_11__["default"],
direction: (prop_types__WEBPACK_IMPORTED_MODULE_3___default().string),
disabled: (prop_types__WEBPACK_IMPORTED_MODULE_3___default().bool),
expandDisabled: (prop_types__WEBPACK_IMPORTED_MODULE_3___default().bool),
expandOnClick: (prop_types__WEBPACK_IMPORTED_MODULE_3___default().bool),
expanded: _js_shapes_listShape_js__WEBPACK_IMPORTED_MODULE_11__["default"],
icons: _js_shapes_iconsShape_js__WEBPACK_IMPORTED_MODULE_9__["default"],
iconsClass: (prop_types__WEBPACK_IMPORTED_MODULE_3___default().string),
id: (prop_types__WEBPACK_IMPORTED_MODULE_3___default().string),
lang: _js_shapes_languageShape_js__WEBPACK_IMPORTED_MODULE_10__["default"],
name: (prop_types__WEBPACK_IMPORTED_MODULE_3___default().string),
nameAsArray: (prop_types__WEBPACK_IMPORTED_MODULE_3___default().bool),
nativeCheckboxes: (prop_types__WEBPACK_IMPORTED_MODULE_3___default().bool),
noCascade: (prop_types__WEBPACK_IMPORTED_MODULE_3___default().bool),
onlyLeafCheckboxes: (prop_types__WEBPACK_IMPORTED_MODULE_3___default().bool),
optimisticToggle: (prop_types__WEBPACK_IMPORTED_MODULE_3___default().bool),
showExpandAll: (prop_types__WEBPACK_IMPORTED_MODULE_3___default().bool),
showNodeIcon: (prop_types__WEBPACK_IMPORTED_MODULE_3___default().bool),
showNodeTitle: (prop_types__WEBPACK_IMPORTED_MODULE_3___default().bool),
onCheck: (prop_types__WEBPACK_IMPORTED_MODULE_3___default().func),
onClick: (prop_types__WEBPACK_IMPORTED_MODULE_3___default().func),
onContextMenu: (prop_types__WEBPACK_IMPORTED_MODULE_3___default().func),
onExpand: (prop_types__WEBPACK_IMPORTED_MODULE_3___default().func)
};
static defaultProps = {
checkKeys: [_js_constants_js__WEBPACK_IMPORTED_MODULE_13__.KEYS.SPACEBAR, _js_constants_js__WEBPACK_IMPORTED_MODULE_13__.KEYS.ENTER],
checkModel: _js_constants_js__WEBPACK_IMPORTED_MODULE_13__.CHECK_MODEL.LEAF,
checked: [],
direction: 'ltr',
disabled: false,
expandDisabled: false,
expandOnClick: false,
expanded: [],
icons: defaultIcons,
iconsClass: 'fa5',
id: null,
lang: _js_lang_default_js__WEBPACK_IMPORTED_MODULE_8__["default"],
name: undefined,
nameAsArray: false,
nativeCheckboxes: false,
noCascade: false,
onlyLeafCheckboxes: false,
optimisticToggle: true,
showExpandAll: false,
showNodeIcon: true,
showNodeTitle: false,
onCheck: () => {},
onClick: null,
onContextMenu: null,
onExpand: () => {}
};
constructor(props) {
super(props);
const model = new _js_NodeModel_js__WEBPACK_IMPORTED_MODULE_15__["default"](props);
model.flattenNodes(props.nodes);
model.deserializeLists({
checked: props.checked,
expanded: props.expanded
});
this.state = {
model,
prevProps: props
};
this.onCheck = this.onCheck.bind(this);
this.onContextMenu = this.onContextMenu.bind(this);
this.onExpand = this.onExpand.bind(this);
this.onNodeClick = this.onNodeClick.bind(this);
this.onExpandAll = this.onExpandAll.bind(this);
this.onCollapseAll = this.onCollapseAll.bind(this);
}
static getDerivedStateFromProps(newProps, prevState) {
const {
model,
prevProps
} = prevState;
const {
disabled,
nodes
} = newProps;
const newState = {
...prevState,
prevProps: newProps
};
// Apply new properties to model
model.setProps(newProps);
// Since flattening nodes is an expensive task, only update when there is a node change
if (!(0,fast_equals__WEBPACK_IMPORTED_MODULE_1__.deepEqual)(prevProps.nodes, nodes) || prevProps.disabled !== disabled) {
model.reset();
model.flattenNodes(nodes);
}
model.deserializeLists({
checked: newProps.checked,
expanded: newProps.expanded
});
return newState;
}
onContextMenu(node) {
const {
onContextMenu
} = this.props;
return event => {
onContextMenu(event, node);
};
}
onCheck(nodeInfo) {
const {
checkModel,
noCascade,
onCheck
} = this.props;
const {
model
} = this.state;
const newModel = model.clone();
const node = newModel.getNode(nodeInfo.value);
newModel.toggleChecked(nodeInfo, nodeInfo.checked, checkModel, noCascade);
onCheck(newModel.serializeList('checked'), {
...node,
...nodeInfo
});
}
onExpand(nodeInfo) {
const {
onExpand
} = this.props;
const {
model
} = this.state;
const newModel = model.clone();
const node = newModel.getNode(nodeInfo.value);
newModel.toggleNode(nodeInfo.value, 'expanded', nodeInfo.expanded);
onExpand(newModel.serializeList('expanded'), {
...node,
...nodeInfo
});
}
onNodeClick(nodeInfo) {
const {
onClick
} = this.props;
const {
model
} = this.state;
const node = model.getNode(nodeInfo.value);
onClick({
...node,
...nodeInfo
});
}
onExpandAll() {
this.expandAllNodes();
}
onCollapseAll() {
this.expandAllNodes(false);
}
expandAllNodes(expand = true) {
const {
onExpand
} = this.props;
const {
model
} = this.state;
onExpand(model.clone().expandAllNodes(expand).serializeList('expanded'));
}
determineShallowCheckState(node, noCascade) {
const {
model
} = this.state;
const flatNode = model.getNode(node.value);
if (flatNode.isLeaf || noCascade || node.children.length === 0) {
// Note that an empty parent node tracks its own state
return flatNode.checked ? 1 : 0;
}
if (this.isEveryChildChecked(node)) {
return 1;
}
if (this.isSomeChildChecked(node)) {
return 2;
}
return 0;
}
isEveryChildChecked(node) {
const {
model
} = this.state;
return node.children.every(child => model.getNode(child.value).checkState === 1);
}
isSomeChildChecked(node) {
const {
model
} = this.state;
return node.children.some(child => model.getNode(child.value).checkState > 0);
}
renderTreeNodes(nodes, parent = {}) {
const {
checkKeys,
expandDisabled,
expandOnClick,
id,
noCascade,
onClick,
onlyLeafCheckboxes,
optimisticToggle,
showNodeTitle,
showNodeIcon
} = this.props;
const {
model
} = this.state;
const treeNodes = nodes.map(node => {
const key = node.value;
const flatNode = model.getNode(node.value);
const children = flatNode.isParent ? this.renderTreeNodes(node.children, node) : null;
// Determine the check state after all children check states have been determined
// This is done during rendering as to avoid an additional loop during the
// deserialization of the `checked` property
flatNode.checkState = this.determineShallowCheckState(node, noCascade);
// Show checkbox only if this is a leaf node or showCheckbox is true
const showCheckbox = onlyLeafCheckboxes ? flatNode.isLeaf : flatNode.showCheckbox;
// Render only if parent is expanded or if there is no root parent
const parentExpanded = parent.value ? model.getNode(parent.value).expanded : true;
if (!parentExpanded) {
return null;
}
// Prepare node information for context menu usage
const nodeContext = {
...node,
checked: flatNode.checkState,
expanded: flatNode.expanded
};
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_4___default().createElement(_js_components_TreeNode_jsx__WEBPACK_IMPORTED_MODULE_7__["default"], {
key: key,
checkKeys: checkKeys,
checked: flatNode.checkState,
className: node.className,
disabled: flatNode.disabled,
expandDisabled: expandDisabled,
expandOnClick: expandOnClick,
expanded: flatNode.expanded,
icon: node.icon,
isLeaf: flatNode.isLeaf,
isParent: flatNode.isParent,
label: node.label,
optimisticToggle: optimisticToggle,
showCheckbox: showCheckbox,
showNodeIcon: showNodeIcon,
title: showNodeTitle ? node.title || node.label : node.title,
treeId: id,
value: node.value,
onCheck: this.onCheck,
onClick: onClick && this.onNodeClick,
onContextMenu: this.onContextMenu(nodeContext),
onExpand: this.onExpand
}, children);
});
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_4___default().createElement("ol", null, treeNodes);
}
renderGlobalOptions() {
const {
showExpandAll
} = this.props;
return showExpandAll ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_4___default().createElement(_js_components_GlobalActions_jsx__WEBPACK_IMPORTED_MODULE_5__["default"], {
onCollapseAll: this.onCollapseAll,
onExpandAll: this.onExpandAll
}) : null;
}
renderHiddenInput() {
const {
checked,
name,
nameAsArray
} = this.props;
return name !== undefined ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_4___default().createElement(_js_components_HiddenInput_jsx__WEBPACK_IMPORTED_MODULE_6__["default"], {
checked: checked,
name: name,
nameAsArray: nameAsArray
}) : null;
}
render() {
const {
direction,
disabled,
icons,
iconsClass,
id,
lang,
nodes,
nativeCheckboxes
} = this.props;
const mergedLang = combineMemoized(lang, _js_lang_default_js__WEBPACK_IMPORTED_MODULE_8__["default"]);
const mergedIcons = combineMemoized(icons, defaultIcons);
const treeNodes = this.renderTreeNodes(nodes);
const className = classnames__WEBPACK_IMPORTED_MODULE_0___default()({
'react-checkbox-tree': true,
'rct-disabled': disabled,
[`rct-icons-${iconsClass}`]: true,
'rct-native-display': nativeCheckboxes,
'rct-direction-rtl': direction === 'rtl'
});
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_4___default().createElement(_js_contexts_js__WEBPACK_IMPORTED_MODULE_14__.LanguageContext.Provider, {
value: mergedLang
}, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_4___default().createElement(_js_contexts_js__WEBPACK_IMPORTED_MODULE_14__.IconContext.Provider, {
value: mergedIcons
}, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_4___default().createElement("div", {
className: className,
id: id
}, this.renderGlobalOptions(), this.renderHiddenInput(), treeNodes)));
}
}
/* harmony default export */ __webpack_exports__["default"] = (CheckboxTree);
/***/ }),
/* 2 */
/***/ (function(module, exports) {
var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*!
Copyright (c) 2018 Jed Watson.
Licensed under the MIT License (MIT), see
http://jedwatson.github.io/classnames
*/
/* global define */
(function () {
'use strict';
var hasOwn = {}.hasOwnProperty;
function classNames () {
var classes = '';
for (var i = 0; i < arguments.length; i++) {
var arg = arguments[i];
if (arg) {
classes = appendClass(classes, parseValue(arg));
}
}
return classes;
}
function parseValue (arg) {
if (typeof arg === 'string' || typeof arg === 'number') {
return arg;
}
if (typeof arg !== 'object') {
return '';
}
if (Array.isArray(arg)) {
return classNames.apply(null, arg);
}
if (arg.toString !== Object.prototype.toString && !arg.toString.toString().includes('[native code]')) {
return arg.toString();
}
var classes = '';
for (var key in arg) {
if (hasOwn.call(arg, key) && arg[key]) {
classes = appendClass(classes, key);
}
}
return classes;
}
function appendClass (value, newClass) {
if (!newClass) {
return value;
}
if (value) {
return value + ' ' + newClass;
}
return value + newClass;
}
if ( true && module.exports) {
classNames.default = classNames;
module.exports = classNames;
} else if (true) {
// register as 'classnames', consistent with npm package name
!(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = (function () {
return classNames;
}).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__),
__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
} else // removed by dead control flow
{}
}());
/***/ }),
/* 3 */
/***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ circularDeepEqual: function() { return /* binding */ circularDeepEqual; },
/* harmony export */ circularShallowEqual: function() { return /* binding */ circularShallowEqual; },
/* harmony export */ createCustomEqual: function() { return /* binding */ createCustomEqual; },
/* harmony export */ deepEqual: function() { return /* binding */ deepEqual; },
/* harmony export */ sameValueEqual: function() { return /* binding */ sameValueEqual; },
/* harmony export */ sameValueZeroEqual: function() { return /* binding */ sameValueZeroEqual; },
/* harmony export */ shallowEqual: function() { return /* binding */ shallowEqual; },
/* harmony export */ strictCircularDeepEqual: function() { return /* binding */ strictCircularDeepEqual; },
/* harmony export */ strictCircularShallowEqual: function() { return /* binding */ strictCircularShallowEqual; },
/* harmony export */ strictDeepEqual: function() { return /* binding */ strictDeepEqual; },
/* harmony export */ strictEqual: function() { return /* binding */ strictEqual; },
/* harmony export */ strictShallowEqual: function() { return /* binding */ strictShallowEqual; }
/* harmony export */ });
const { getOwnPropertyNames, getOwnPropertySymbols } = Object;
// eslint-disable-next-line @typescript-eslint/unbound-method
const { hasOwnProperty } = Object.prototype;
/**
* Combine two comparators into a single comparators.
*/
function combineComparators(comparatorA, comparatorB) {
return function isEqual(a, b, state) {
return comparatorA(a, b, state) && comparatorB(a, b, state);
};
}
/**
* Wrap the provided `areItemsEqual` method to manage the circular state, allowing
* for circular references to be safely included in the comparison without creating
* stack overflows.
*/
function createIsCircular(areItemsEqual) {
return function isCircular(a, b, state) {
if (!a || !b || typeof a !== 'object' || typeof b !== 'object') {
return areItemsEqual(a, b, state);
}
const { cache } = state;
const cachedA = cache.get(a);
const cachedB = cache.get(b);
if (cachedA && cachedB) {
return cachedA === b && cachedB === a;
}
cache.set(a, b);
cache.set(b, a);
const result = areItemsEqual(a, b, state);
cache.delete(a);
cache.delete(b);
return result;
};
}
/**
* Get the properties to strictly examine, which include both own properties that are
* not enumerable and symbol properties.
*/
function getStrictProperties(object) {
return getOwnPropertyNames(object).concat(getOwnPropertySymbols(object));
}
/**
* Whether the object contains the property passed as an own property.
*/
const hasOwn =
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
Object.hasOwn || ((object, property) => hasOwnProperty.call(object, property));
const PREACT_VNODE = '__v';
const PREACT_OWNER = '__o';
const REACT_OWNER = '_owner';
const { getOwnPropertyDescriptor, keys } = Object;
/**
* Whether the values passed are equal based on a [SameValue](https://262.ecma-international.org/7.0/#sec-samevalue) basis.
* Simplified, this maps to if the two values are referentially equal to one another (`a === b`) or both are `NaN`.
*
* @note
* When available in the environment, this is just a re-export of the global
* [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) method.
*/
const sameValueEqual =
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
Object.is
|| function sameValueEqual(a, b) {
return a === b ? a !== 0 || 1 / a === 1 / b : a !== a && b !== b;
};
/**
* Whether the values passed are equal based on a [SameValue](https://262.ecma-international.org/7.0/#sec-samevaluezero) basis.
* Simplified, this maps to if the two values are referentially equal to one another (`a === b`), both are `NaN`, or both
* are either positive or negative zero.
*/
function sameValueZeroEqual(a, b) {
return a === b || (a !== a && b !== b);
}
/**
* Whether the values passed are equal based on a
* [Strict Equality Comparison](https://262.ecma-international.org/7.0/#sec-strict-equality-comparison) basis.
* Simplified, this maps to if the two values are referentially equal to one another (`a === b`).
*
* @note
* This is mainly available as a convenience function, such as being a default when a function to determine equality between
* two objects is used.
*/
function strictEqual(a, b) {
return a === b;
}
/**
* Whether the array buffers are equal in value.
*/
function areArrayBuffersEqual(a, b) {
return a.byteLength === b.byteLength && areTypedArraysEqual(new Uint8Array(a), new Uint8Array(b));
}
/**
* Whether the arrays are equal in value.
*/
function areArraysEqual(a, b, state) {
let index = a.length;
if (b.length !== index) {
return false;
}
while (index-- > 0) {
if (!state.equals(a[index], b[index], index, index, a, b, state)) {
return false;
}
}
return true;
}
/**
* Whether the dataviews are equal in value.
*/
function areDataViewsEqual(a, b) {
return (a.byteLength === b.byteLength
&& areTypedArraysEqual(new Uint8Array(a.buffer, a.byteOffset, a.byteLength), new Uint8Array(b.buffer, b.byteOffset, b.byteLength)));
}
/**
* Whether the dates passed are equal in value.
*/
function areDatesEqual(a, b) {
return sameValueEqual(a.getTime(), b.getTime());
}
/**
* Whether the errors passed are equal in value.
*/
function areErrorsEqual(a, b) {
return a.name === b.name && a.message === b.message && a.cause === b.cause && a.stack === b.stack;
}
/**
* Whether the `Map`s are equal in value.
*/
function areMapsEqual(a, b, state) {
const size = a.size;
if (size !== b.size) {
return false;
}
if (!size) {
return true;
}
const matchedIndices = new Array(size);
const aIterable = a.entries();
let aResult;
let bResult;
let index = 0;
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
while ((aResult = aIterable.next())) {
if (aResult.done) {
break;
}
const bIterable = b.entries();
let hasMatch = false;
let matchIndex = 0;
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
while ((bResult = bIterable.next())) {
if (bResult.done) {
break;
}
if (matchedIndices[matchIndex]) {
matchIndex++;
continue;
}
const aEntry = aResult.value;
const bEntry = bResult.value;
if (state.equals(aEntry[0], bEntry[0], index, matchIndex, a, b, state)
&& state.equals(aEntry[1], bEntry[1], aEntry[0], bEntry[0], a, b, state)) {
hasMatch = matchedIndices[matchIndex] = true;
break;
}
matchIndex++;
}
if (!hasMatch) {
return false;
}
index++;
}
return true;
}
/**
* Whether the objects are equal in value.
*/
function areObjectsEqual(a, b, state) {
const properties = keys(a);
let index = properties.length;
if (keys(b).length !== index) {
return false;
}
// Decrementing `while` showed faster results than either incrementing or
// decrementing `for` loop and than an incrementing `while` loop. Declarative
// methods like `some` / `every` were not used to avoid incurring the garbage
// cost of anonymous callbacks.
while (index-- > 0) {
if (!isPropertyEqual(a, b, state, properties[index])) {
return false;
}
}
return true;
}
/**
* Whether the objects are equal in value with strict property checking.
*/
function areObjectsEqualStrict(a, b, state) {
const properties = getStrictProperties(a);
let index = properties.length;
if (getStrictProperties(b).length !== index) {
return false;
}
let property;
let descriptorA;
let descriptorB;
// Decrementing `while` showed faster results than either incrementing or
// decrementing `for` loop and than an incrementing `while` loop. Declarative
// methods like `some` / `every` were not used to avoid incurring the garbage
// cost of anonymous callbacks.
while (index-- > 0) {
property = properties[index];
if (!isPropertyEqual(a, b, state, property)) {
return false;
}
descriptorA = getOwnPropertyDescriptor(a, property);
descriptorB = getOwnPropertyDescriptor(b, property);
if ((descriptorA || descriptorB)
&& (!descriptorA
|| !descriptorB
|| descriptorA.configurable !== descriptorB.configurable
|| descriptorA.enumerable !== descriptorB.enumerable
|| descriptorA.writable !== descriptorB.writable)) {
return false;
}
}
return true;
}
/**
* Whether the primitive wrappers passed are equal in value.
*/
function arePrimitiveWrappersEqual(a, b) {
return sameValueEqual(a.valueOf(), b.valueOf());
}
/**
* Whether the regexps passed are equal in value.
*/
function areRegExpsEqual(a, b) {
return a.source === b.source && a.flags === b.flags;
}
/**
* Whether the `Set`s are equal in value.
*/
function areSetsEqual(a, b, state) {
const size = a.size;
if (size !== b.size) {
return false;
}
if (!size) {
return true;
}
const matchedIndices = new Array(size);
const aIterable = a.values();
let aResult;
let bResult;
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
while ((aResult = aIterable.next())) {
if (aResult.done) {
break;
}
const bIterable = b.values();
let hasMatch = false;
let matchIndex = 0;
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
while ((bResult = bIterable.next())) {
if (bResult.done) {
break;
}
if (!matchedIndices[matchIndex]
&& state.equals(aResult.value, bResult.value, aResult.value, bResult.value, a, b, state)) {
hasMatch = matchedIndices[matchIndex] = true;
break;
}
matchIndex++;
}
if (!hasMatch) {
return false;
}
}
return true;
}
/**
* Whether the TypedArray instances are equal in value.
*/
function areTypedArraysEqual(a, b) {
let index = a.byteLength;
if (b.byteLength !== index || a.byteOffset !== b.byteOffset) {
return false;
}
while (index-- > 0) {
if (a[index] !== b[index]) {
return false;
}
}
return true;
}
/**
* Whether the URL instances are equal in value.
*/
function areUrlsEqual(a, b) {
return (a.hostname === b.hostname
&& a.pathname === b.pathname
&& a.protocol === b.protocol
&& a.port === b.port
&& a.hash === b.hash
&& a.username === b.username
&& a.password === b.password);
}
function isPropertyEqual(a, b, state, property) {
if ((property === REACT_OWNER || property === PREACT_OWNER || property === PREACT_VNODE)
&& (a.$$typeof || b.$$typeof)) {
return true;
}
return hasOwn(b, property) && state.equals(a[property], b[property], property, property, a, b, state);
}
// eslint-disable-next-line @typescript-eslint/unbound-method
const toString = Object.prototype.toString;
/**
* Create a comparator method based on the type-specific equality comparators passed.
*/
function createEqualityComparator(config) {
const supportedComparatorMap = createSupportedComparatorMap(config);
const { areArraysEqual, areDatesEqual, areFunctionsEqual, areMapsEqual, areNumbersEqual, areObjectsEqual, areRegExpsEqual, areSetsEqual, getUnsupportedCustomComparator, } = config;
/**
* compare the value of the two objects and return true if they are equivalent in values
*/
return function comparator(a, b, state) {
// If the items are strictly equal, no need to do a value comparison.
if (a === b) {
return true;
}
// If either of the items are nullish and fail the strictly equal check
// above, then they must be unequal.
if (a == null || b == null) {
return false;
}
const type = typeof a;
if (type !== typeof b) {
return false;
}
if (type !== 'object') {
if (type === 'number' || type === 'bigint') {
return areNumbersEqual(a, b, state);
}
if (type === 'function') {
return areFunctionsEqual(a, b, state);
}
// If a primitive value that is not strictly equal, it must be unequal.
return false;
}
const constructor = a.constructor;
// Checks are listed in order of commonality of use-case:
// 1. Common complex object types (plain object, array)
// 2. Common data values (date, regexp)
// 3. Less-common complex object types (map, set)
// 4. Less-common data values (promise, primitive wrappers)
// Inherently this is both subjective and assumptive, however
// when reviewing comparable libraries in the wild this order
// appears to be generally consistent.
// Constructors should match, otherwise there is potential for false positives
// between class and subclass or custom object and POJO.
if (constructor !== b.constructor) {
return false;
}
// Try to fast-path equality checks for other complex object types in the
// same realm to avoid capturing the string tag. Strict equality is used
// instead of `instanceof` because it is more performant for the common
// use-case. If someone is creating a subclass from a native class, it will be
// handled with the string tag comparison.
if (constructor === Object) {
return areObjectsEqual(a, b, state);
}
if (constructor === Array) {
return areArraysEqual(a, b, state);
}
if (constructor === Date) {
return areDatesEqual(a, b, state);
}
if (constructor === RegExp) {
return areRegExpsEqual(a, b, state);
}
if (constructor === Map) {
return areMapsEqual(a, b, state);
}
if (constructor === Set) {
return areSetsEqual(a, b, state);
}
if (constructor === Promise) {
// Avoid tag checks for promise values, since we know if they are not referentially equal
// then they are not equal.
return false;
}
// `isArray()` works on subclasses and is cross-realm, so we can avoid capturing
// the string tag or doing an `instanceof` in edge cases.
if (Array.isArray(a)) {
return areArraysEqual(a, b, state);
}
// Since this is a custom object, capture the string tag to determining its type.
// This is reasonably performant in modern environments like v8 and SpiderMonkey.
const tag = toString.call(a);
const supportedComparator = supportedComparatorMap[tag];
if (supportedComparator) {
return supportedComparator(a, b, state);
}
const unsupportedCustomComparator = getUnsupportedCustomComparator && getUnsupportedCustomComparator(a, b, state, tag);
if (unsupportedCustomComparator) {
return unsupportedCustomComparator(a, b, state);
}
// If not matching any tags that require a specific type of comparison, then we hard-code false because
// the only thing remaining is strict equality, which has already been compared. This is for a few reasons:
// - Certain types that cannot be introspected (e.g., `WeakMap`). For these types, this is the only
// comparison that can be made.
// - For types that can be introspected but do not have an objective definition of what
// equality is (`Error`, etc.), the subjective decision is to be conservative and strictly compare.
// In all cases, these decisions should be reevaluated based on changes to the language and
// common development practices.
return false;
};
}
/**
* Create the configuration object used for building comparators.
*/
function createEqualityComparatorConfig({ circular, createCustomConfig, strict, }) {
let config = {
areArrayBuffersEqual,
areArraysEqual: strict ? areObjectsEqualStrict : areArraysEqual,
areDataViewsEqual,
areDatesEqual: areDatesEqual,
areErrorsEqual: areErrorsEqual,
areFunctionsEqual: strictEqual,
areMapsEqual: strict ? combineComparators(areMapsEqual, areObjectsEqualStrict) : areMapsEqual,
areNumbersEqual: sameValueEqual,
areObjectsEqual: strict ? areObjectsEqualStrict : areObjectsEqual,
arePrimitiveWrappersEqual: arePrimitiveWrappersEqual,
areRegExpsEqual: areRegExpsEqual,
areSetsEqual: strict ? combineComparators(areSetsEqual, areObjectsEqualStrict) : areSetsEqual,
areTypedArraysEqual: strict
? combineComparators(areTypedArraysEqual, areObjectsEqualStrict)
: areTypedArraysEqual,
areUrlsEqual: areUrlsEqual,
getUnsupportedCustomComparator: undefined,
};
if (createCustomConfig) {
config = Object.assign({}, config, createCustomConfig(config));
}
if (circular) {
const areArraysEqual = createIsCircular(config.areArraysEqual);
const areMapsEqual = createIsCircular(config.areMapsEqual);
const areObjectsEqual = createIsCircular(config.areObjectsEqual);
const areSetsEqual = createIsCircular(config.areSetsEqual);
config = Object.assign({}, config, {
areArraysEqual,
areMapsEqual,
areObjectsEqual,
areSetsEqual,
});
}
return config;
}
/**
* Default equality comparator pass-through, used as the standard `isEqual` creator for
* use inside the built comparator.
*/
function createInternalEqualityComparator(compare) {
return function (a, b, _indexOrKeyA, _indexOrKeyB, _parentA, _parentB, state) {
return compare(a, b, state);
};
}
/**
* Create the `isEqual` function used by the consuming application.
*/
function createIsEqual({ circular, comparator, createState, equals, strict }) {
if (createState) {
return function isEqual(a, b) {
const { cache = circular ? new WeakMap() : undefined, meta } = createState();
return comparator(a, b, {
cache,
equals,
meta,
strict,
});
};
}
if (circular) {
return function isEqual(a, b) {
return comparator(a, b, {
cache: new WeakMap(),
equals,
meta: undefined,
strict,
});
};
}
const state = {
cache: undefined,
equals,
meta: undefined,
strict,
};
return function isEqual(a, b) {
return comparator(a, b, state);
};
}
/**
* Create a map of `toString()` values to their respective handlers for `tag`-based lookups.
*/
function createSupportedComparatorMap({ areArrayBuffersEqual, areArraysEqual, areDataViewsEqual, areDatesEqual, areErrorsEqual, areFunctionsEqual, areMapsEqual, areNumbersEqual, areObjectsEqual, arePrimitiveWrappersEqual, areRegExpsEqual, areSetsEqual, areTypedArraysEqual, areUrlsEqual, }) {
return {
'[object Arguments]': areObjectsEqual,
'[object Array]': areArraysEqual,
'[object ArrayBuffer]': areArrayBuffersEqual,
'[object AsyncGeneratorFunction]': areFunctionsEqual,
'[object BigInt]': areNumbersEqual,
'[object BigInt64Array]': areTypedArraysEqual,
'[object BigUint64Array]': areTypedArraysEqual,
'[object Boolean]': arePrimitiveWrappersEqual,
'[object DataView]': areDataViewsEqual,
'[object Date]': areDatesEqual,
// If an error tag, it should be tested explicitly. Like RegExp, the properties are not
// enumerable, and therefore will give false positives if tested like a standard object.
'[object Error]': areErrorsEqual,
'[object Float16Array]': areTypedArraysEqual,
'[object Float32Array]': areTypedArraysEqual,
'[object Float64Array]': areTypedArraysEqual,
'[object Function]': areFunctionsEqual,
'[object GeneratorFunction]': areFunctionsEqual,
'[object Int8Array]': areTypedArraysEqual,
'[object Int16Array]': areTypedArraysEqual,
'[object Int32Array]': areTypedArraysEqual,
'[object Map]': areMapsEqual,
'[object Number]': arePrimitiveWrappersEqual,
'[object Object]': (a, b, state) =>
// The exception for value comparison is custom `Promise`-like class instances. These should
// be treated the same as standard `Promise` objects, which means strict equality, and if
// it reaches this point then that strict equality comparison has already failed.
typeof a.then !== 'function' && typeof b.then !== 'function' && areObjectsEqual(a, b, state),
// For RegExp, the properties are not enumerable, and therefore will give false positives if
// tested like a standard object.
'[object RegExp]': areRegExpsEqual,
'[object Set]': areSetsEqual,
'[object String]': arePrimitiveWrappersEqual,
'[object URL]': areUrlsEqual,
'[object Uint8Array]': areTypedArraysEqual,
'[object Uint8ClampedArray]': areTypedArraysEqual,
'[object Uint16Array]': areTypedArraysEqual,
'[object Uint32Array]': areTypedArraysEqual,
};
}
/**
* Whether the items passed are deeply-equal in value.
*/
const deepEqual = createCustomEqual();
/**
* Whether the items passed are deeply-equal in value based on strict comparison.
*/
const strictDeepEqual = createCustomEqual({ strict: true });
/**
* Whether the items passed are deeply-equal in value, including circular references.
*/
const circularDeepEqual = createCustomEqual({ circular: true });
/**
* Whether the items passed are deeply-equal in value, including circular references,
* based on strict comparison.
*/
const strictCircularDeepEqual = createCustomEqual({
circular: true,
strict: true,
});
/**
* Whether the items passed are shallowly-equal in value.
*/
const shallowEqual = createCustomEqual({
createInternalComparator: () => sameValueEqual,
});
/**
* Whether the items passed are shallowly-equal in value based on strict comparison
*/
const strictShallowEqual = createCustomEqual({
strict: true,
createInternalComparator: () => sameValueEqual,
});
/**
* Whether the items passed are shallowly-equal in value, including circular references.
*/
const circularShallowEqual = createCustomEqual({
circular: true,
createInternalComparator: () => sameValueEqual,
});
/**
* Whether the items passed are shallowly-equal in value, including circular references,
* based on strict comparison.
*/
const strictCircularShallowEqual = createCustomEqual({
circular: true,
createInternalComparator: () => sameValueEqual,
strict: true,
});
/**
* Create a custom equality comparison method.
*
* This can be done to create very targeted comparisons in extreme hot-path scenarios
* where the standard methods are not performant enough, but can also be used to provide
* support for legacy environments that do not support expected features like
* `RegExp.prototype.flags` out of the box.
*/
function createCustomEqual(options = {}) {
const { circular = false, createInternalComparator: createCustomInternalComparator, createState, strict = false, } = options;
const config = createEqualityComparatorConfig(options);
const comparator = createEqualityComparator(config);
const equals = createCustomInternalComparator
? createCustomInternalComparator(comparator)
: createInternalEqualityComparator(comparator);
return createIsEqual({ circular, comparator, createState, equals, strict });
}
/***/ }),
/* 4 */
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
/**
* lodash (Custom Build) <https://lodash.com/>
* Build: `lodash modularize exports="npm" -o ./`
* Copyright jQuery Foundation and other contributors <https://jquery.org/>
* Released under MIT license <https://lodash.com/license>
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
* Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
*/
/** Used as the `TypeError` message for "Functions" methods. */
var FUNC_ERROR_TEXT = 'Expected a function';
/** Used to stand-in for `undefined` hash values. */
var HASH_UNDEFINED = '__lodash_hash_undefined__';
/** `Object#toString` result references. */
var funcTag = '[object Function]',
genTag = '[object GeneratorFunction]';
/**
* Used to match `RegExp`
* [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).
*/
var reRegExpChar = /[\\^$.*+?()[\]{}|]/g;
/** Used to detect host constructors (Safari). */
var reIsHostCtor = /^\[object .+?Constructor\]$/;
/** Detect free variable `global` from Node.js. */
var freeGlobal = typeof __webpack_require__.g == 'object' && __webpack_require__.g && __webpack_require__.g.Object === Object && __webpack_require__.g;
/** Detect free variable `self`. */
var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
/** Used as a reference to the global object. */
var root = freeGlobal || freeSelf || Function('return this')();
/**
* Gets the value at `key` of `object`.
*
* @private
* @param {Object} [object] The object to query.
* @param {string} key The key of the property to get.
* @returns {*} Returns the property value.
*/
function getValue(object, key) {
return object == null ? undefined : object[key];
}
/**
* Checks if `value` is a host object in IE < 9.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a host object, else `false`.
*/
function isHostObject(value) {
// Many host objects are `Object` objects that can coerce to strings
// despite having improperly defined `toString` methods.
var result = false;
if (value != null && typeof value.toString != 'function') {
try {
result = !!(value + '');
} catch (e) {}
}
return result;
}
/** Used for built-in method references. */
var arrayProto = Array.prototype,
funcProto = Function.prototype,
objectProto = Object.prototype;
/** Used to detect overreaching core-js shims. */
var coreJsData = root['__core-js_shared__'];
/** Used to detect methods masquerading as native. */
var maskSrcKey = (function() {
var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || '');
return uid ? ('Symbol(src)_1.' + uid) : '';
}());
/** Used to resolve the decompiled source of functions. */
var funcToString = funcProto.toString;
/** Used to check objects for own properties. */
var hasOwnProperty = objectProto.hasOwnProperty;
/**
* Used to resolve the
* [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
* of values.
*/
var objectToString = objectProto.toString;
/** Used to detect if a method is native. */
var reIsNative = RegExp('^' +
funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&')
.replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
);
/** Built-in value references. */
var splice = arrayProto.splice;
/* Built-in method references that are verified to be native. */
var Map = getNative(root, 'Map'),
nativeCreate = getNative(Object, 'create');
/**
* Creates a hash object.
*
* @private
* @constructor
* @param {Array} [entries] The key-value pairs to cache.
*/
function Hash(entries) {
var index = -1,
length = entries ? entries.length : 0;
this.clear();
while (++index < length) {
var entry = entries[index];
this.set(entry[0], entry[1]);
}
}
/**
* Removes all key-value entries from the hash.
*
* @private
* @name clear
* @memberOf Hash
*/
function hashClear() {
this.__data__ = nativeCreate ? nativeCreate(null) : {};
}
/**
* Removes `key` and its value from the hash.
*
* @private
* @name delete
* @memberOf Hash
* @param {Object} hash The hash to modify.
* @param {string} key The key of the value to remove.
* @returns {boolean} Returns `true` if the entry was removed, else `false`.
*/
function hashDelete(key) {
return this.has(key) && delete this.__data__[key];
}
/**
* Gets the hash value for `key`.
*
* @private
* @name get
* @memberOf Hash
* @param {string} key The key of the value to get.
* @returns {*} Returns the entry value.
*/
function hashGet(key) {
var data = this.__data__;
if (nativeCreate) {
var result = data[key];
return result === HASH_UNDEFINED ? undefined : result;
}
return hasOwnProperty.call(data, key) ? data[key] : undefined;
}
/**
* Checks if a hash value for `key` exists.
*
* @private
* @name has
* @memberOf Hash
* @param {string} key The key of the entry to check.
* @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
*/
function hashHas(key) {
var data = this.__data__;
return nativeCreate ? data[key] !== undefined : hasOwnProperty.call(data, key);
}
/**
* Sets the hash `key` to `value`.
*
* @private
* @name set
* @memberOf Hash
* @param {string} key The key of the value to set.
* @param {*} value The value to set.
* @returns {Object} Returns the hash instance.
*/
function hashSet(key, value) {
var data = this.__data__;
data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value;
return this;
}
// Add methods to `Hash`.
Hash.prototype.clear = hashClear;
Hash.prototype['delete'] = hashDelete;
Hash.prototype.get = hashGet;
Hash.prototype.has = hashHas;
Hash.prototype.set = hashSet;
/**
* Creates an list cache object.
*
* @private
* @constructor
* @param {Array} [entries] The key-value pairs to cache.
*/
function ListCache(entries) {
var index = -1,
length = entries ? entries.length : 0;
this.clear();
while (++index < length) {
var entry = entries[index];
this.set(entry[0], entry[1]);
}
}
/**
* Removes all key-value entries from the list cache.
*
* @private
* @name clear
* @memberOf ListCache
*/
function listCacheClear() {
this.__data__ = [];
}
/**
* Removes `key` and its value from the list cache.
*
* @private
* @name delete
* @memberOf ListCache
* @param {string} key The key of the value to remove.
* @returns {boolean} Returns `true` if the entry was removed, else `false`.
*/
function listCacheDelete(key) {
var data = this.__data__,
index = assocIndexOf(data, key);
if (index < 0) {
return false;
}
var lastIndex = data.length - 1;
if (index == lastIndex) {
data.pop();
} else {
splice.call(data, index, 1);
}
return true;
}
/**
* Gets the list cache value for `key`.
*
* @private
* @name get
* @memberOf ListCache
* @param {string} key The key of the value to get.
* @returns {*} Returns the entry value.
*/
function listCacheGet(key) {
var data = this.__data__,
index = assocIndexOf(data, key);
return index < 0 ? undefined : data[index][1];
}
/**
* Checks if a list cache value for `key` exists.
*
* @private
* @name has
* @memberOf ListCache
* @param {string} key The key of the entry to check.
* @returns {boolean}