UNPKG

react-checkbox-tree

Version:
1,430 lines (1,343 loc) 139 kB
/*! * react-checkbox-tree - v2.0.2 * 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}