UNPKG

@handsontable/react

Version:

Best Data Grid for React with Spreadsheet Look and Feel.

1,288 lines (1,272 loc) • 58.1 kB
/*! * Copyright (c) HANDSONCODE sp. z o. o. * * HANDSONTABLE is a software distributed by HANDSONCODE sp. z o. o., a Polish corporation based in * Gdynia, Poland, at Aleja Zwyciestwa 96-98, registered by the District Court in Gdansk under number * 538651, EU tax ID number: PL5862294002, share capital: PLN 62,800.00. * * This software is protected by applicable copyright laws, including international treaties, and dual- * licensed - depending on whether your use for commercial purposes, meaning intended for or * resulting in commercial advantage or monetary compensation, or not. * * If your use is strictly personal or solely for evaluation purposes, meaning for the purposes of testing * the suitability, performance, and usefulness of this software outside the production environment, * you agree to be bound by the terms included in the "handsontable-non-commercial-license.pdf" file. * * Your use of this software for commercial purposes is subject to the terms included in an applicable * license agreement. * * In any case, you must not make any such use of this software as to develop software which may be * considered competitive with this software. * * UNLESS EXPRESSLY AGREED OTHERWISE, HANDSONCODE PROVIDES THIS SOFTWARE ON AN "AS IS" * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, AND IN NO EVENT AND UNDER NO * LEGAL THEORY, SHALL HANDSONCODE BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY DIRECT, * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER ARISING FROM * USE OR INABILITY TO USE THIS SOFTWARE. * * Version: 15.2.0 (built at Wed Mar 19 2025 09:42:36 GMT+0100 (Central European Standard Time)) */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react'), require('react-dom'), require('handsontable/base'), require('handsontable/renderers/registry'), require('handsontable/editors/registry')) : typeof define === 'function' && define.amd ? define(['exports', 'react', 'react-dom', 'handsontable/base', 'handsontable/renderers/registry', 'handsontable/editors/registry'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.Handsontable = global.Handsontable || {}, global.Handsontable.react = {}), global.React, global.ReactDOM, global.Handsontable, global.Handsontable.renderers, global.Handsontable.editors)); })(this, (function (exports, React, ReactDOM, Handsontable, registry$1, registry) { 'use strict'; function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; } var React__default = /*#__PURE__*/_interopDefaultCompat(React); var ReactDOM__default = /*#__PURE__*/_interopDefaultCompat(ReactDOM); var Handsontable__default = /*#__PURE__*/_interopDefaultCompat(Handsontable); function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); } function _assertThisInitialized(e) { if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); return e; } function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); } function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); } function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || false, o.configurable = true, "value" in o && (o.writable = true), Object.defineProperty(e, _toPropertyKey(o.key), o); } } function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: false }), e; } function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: true, configurable: true, writable: true }) : e[r] = t, e; } function _getPrototypeOf(t) { return _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) { return t.__proto__ || Object.getPrototypeOf(t); }, _getPrototypeOf(t); } function _inherits(t, e) { if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function"); t.prototype = Object.create(e && e.prototype, { constructor: { value: t, writable: true, configurable: true } }), Object.defineProperty(t, "prototype", { writable: false }), e && _setPrototypeOf(t, e); } function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function () { return !!t; })(); } function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread2(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), true).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; } function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; } function _possibleConstructorReturn(t, e) { if (e && ("object" == typeof e || "function" == typeof e)) return e; if (void 0 !== e) throw new TypeError("Derived constructors may only return object or undefined"); return _assertThisInitialized(t); } function _setPrototypeOf(t, e) { return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) { return t.__proto__ = e, t; }, _setPrototypeOf(t, e); } function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); } function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return (String )(t); } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } var bulkComponentContainer = null; /** * Warning message for the `autoRowSize`/`autoColumnSize` compatibility check. */ var AUTOSIZE_WARNING = 'Your `HotTable` configuration includes `autoRowSize`/`autoColumnSize` options, which are not compatible with ' + ' the component-based renderers`. Disable `autoRowSize` and `autoColumnSize` to prevent row and column misalignment.'; /** * Message for the warning thrown if the Handsontable instance has been destroyed. */ var HOT_DESTROYED_WARNING = 'The Handsontable instance bound to this component was destroyed and cannot be' + ' used properly.'; /** * String identifier for the global-scoped editor components. */ var GLOBAL_EDITOR_SCOPE = 'global'; /** * Default classname given to the wrapper container. */ var DEFAULT_CLASSNAME = 'hot-wrapper-editor-container'; /** * Logs warn to the console if the `console` object is exposed. * * @param {...*} args Values which will be logged. */ function warn() { if (typeof console !== 'undefined') { var _console; (_console = console).warn.apply(_console, arguments); } } /** * Filter out and return elements of the provided `type` from the `HotColumn` component's children. * * @param {React.ReactNode} children HotTable children array. * @param {String} type Either `'hot-renderer'` or `'hot-editor'`. * @returns {Object|null} A child (React node) or `null`, if no child of that type was found. */ function getChildElementByType(children, type) { var childrenArray = React__default["default"].Children.toArray(children); var childrenCount = React__default["default"].Children.count(children); var wantedChild = null; if (childrenCount !== 0) { if (childrenCount === 1 && childrenArray[0].props[type]) { wantedChild = childrenArray[0]; } else { wantedChild = childrenArray.find(function (child) { return child.props[type] !== void 0; }); } } return wantedChild || null; } /** * Get the reference to the original editor class. * * @param {React.ReactElement} editorElement React element of the editor class. * @returns {Function} Original class of the editor component. */ function getOriginalEditorClass(editorElement) { if (!editorElement) { return null; } return editorElement.type.WrappedComponent ? editorElement.type.WrappedComponent : editorElement.type; } /** * Create an editor portal. * * @param {Document} doc Document to be used. * @param {React.ReactElement} editorElement Editor's element. * @returns {React.ReactPortal} The portal for the editor. */ function createEditorPortal(doc, editorElement) { if (typeof doc === 'undefined' || editorElement === null) { return null; } var containerProps = getContainerAttributesProps(editorElement.props, false); containerProps.className = "".concat(DEFAULT_CLASSNAME, " ").concat(containerProps.className); return ReactDOM__default["default"].createPortal(React__default["default"].createElement("div", Object.assign({}, containerProps), editorElement), doc.body); } /** * Get an editor element extended with an instance-emitting method. * * @param {React.ReactNode} children Component children. * @param {Map} editorCache Component's editor cache. * @param {EditorScopeIdentifier} [editorColumnScope] The editor scope (column index or a 'global' string). Defaults to * 'global'. * @returns {React.ReactElement} An editor element containing the additional methods. */ function getExtendedEditorElement(children, editorCache) { var editorColumnScope = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : GLOBAL_EDITOR_SCOPE; var editorElement = getChildElementByType(children, 'hot-editor'); var editorClass = getOriginalEditorClass(editorElement); if (!editorElement) { return null; } return React__default["default"].cloneElement(editorElement, { emitEditorInstance: function emitEditorInstance(editorInstance, editorColumnScope) { if (!editorCache.get(editorClass)) { editorCache.set(editorClass, new Map()); } var cacheEntry = editorCache.get(editorClass); cacheEntry.set(editorColumnScope !== null && editorColumnScope !== void 0 ? editorColumnScope : GLOBAL_EDITOR_SCOPE, editorInstance); }, editorColumnScope: editorColumnScope, isEditor: true }); } /** * Create a react component and render it to an external DOM done. * * @param {React.ReactElement} rElement React element to be used as a base for the component. * @param {Object} props Props to be passed to the cloned element. * @param {Document} [ownerDocument] The owner document to set the portal up into. * @param {String} portalKey The key to be used for the portal. * @param {HTMLElement} [cachedContainer] The cached container to be used for the portal. * @returns {{portal: React.ReactPortal, portalContainer: HTMLElement}} An object containing the portal and its container. */ function createPortal(rElement, props) { var ownerDocument = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : document; var portalKey = arguments.length > 3 ? arguments[3] : undefined; var cachedContainer = arguments.length > 4 ? arguments[4] : undefined; if (!ownerDocument) { ownerDocument = document; } if (!bulkComponentContainer) { bulkComponentContainer = ownerDocument.createDocumentFragment(); } var portalContainer = cachedContainer !== null && cachedContainer !== void 0 ? cachedContainer : ownerDocument.createElement('DIV'); bulkComponentContainer.appendChild(portalContainer); var extendedRendererElement = React__default["default"].cloneElement(rElement, _objectSpread2({ key: "".concat(props.row, "-").concat(props.col) }, props)); return { portal: ReactDOM__default["default"].createPortal(extendedRendererElement, portalContainer, portalKey), portalContainer: portalContainer }; } /** * Get an object containing the `id`, `className` and `style` keys, representing the corresponding props passed to the * component. * * @param {Object} props Object containing the react element props. * @param {Boolean} randomizeId If set to `true`, the function will randomize the `id` property when no `id` was present in the `prop` object. * @returns An object containing the `id`, `className` and `style` keys, representing the corresponding props passed to the * component. */ function getContainerAttributesProps(props) { var randomizeId = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; return { id: props.id || (randomizeId ? 'hot-' + Math.random().toString(36).substring(5) : undefined), className: props.className || '', style: props.style || {} }; } /** * Checks if the environment that the code runs in is a browser. * * @returns {boolean} */ function isCSR() { return typeof window !== 'undefined'; } var SettingsMapper = /*#__PURE__*/function () { function SettingsMapper() { _classCallCheck(this, SettingsMapper); } return _createClass(SettingsMapper, null, [{ key: "getSettings", value: /** * Parse component settings into Handsontable-compatible settings. * * @param {Object} properties Object containing properties from the HotTable object. * @param {Object} additionalSettings Additional settings. * @param {boolean} additionalSettings.isInit Flag determining whether the settings are being set during initialization. * @param {string[]} additionalSettings.initOnlySettingKeys Array of keys that can be set only during initialization. * @returns {Object} Handsontable-compatible settings object. */ function getSettings(properties) { var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, _ref$prevProps = _ref.prevProps, prevProps = _ref$prevProps === void 0 ? {} : _ref$prevProps, _ref$isInit = _ref.isInit, isInit = _ref$isInit === void 0 ? false : _ref$isInit, _ref$initOnlySettingK = _ref.initOnlySettingKeys, initOnlySettingKeys = _ref$initOnlySettingK === void 0 ? [] : _ref$initOnlySettingK; var shouldSkipProp = function shouldSkipProp(key) { // Omit settings that can be set only during initialization and are intentionally modified. if (!isInit && initOnlySettingKeys.includes(key)) { return prevProps[key] === properties[key]; } return false; }; var newSettings = {}; if (properties.settings) { var settings = properties.settings; for (var key in settings) { if (settings.hasOwnProperty(key) && !shouldSkipProp(key)) { newSettings[key] = settings[key]; } } } for (var _key in properties) { if (_key !== 'settings' && _key !== 'children' && !shouldSkipProp(_key) && properties.hasOwnProperty(_key)) { newSettings[_key] = properties[_key]; } } return newSettings; } }]); }(); var HotColumn = /*#__PURE__*/function (_React$Component) { function HotColumn() { _classCallCheck(this, HotColumn); return _callSuper(this, HotColumn, arguments); } _inherits(HotColumn, _React$Component); return _createClass(HotColumn, [{ key: "getSettingsProps", value: /** * Filter out all the internal properties and return an object with just the Handsontable-related props. * * @returns {Object} */ function getSettingsProps() { var _this = this; this.internalProps = ['_componentRendererColumns', '_emitColumnSettings', '_columnIndex', '_getChildElementByType', '_getRendererWrapper', '_getEditorClass', '_getEditorCache', '_getOwnerDocument', 'hot-renderer', 'hot-editor', 'children']; return Object.keys(this.props).filter(function (key) { return !_this.internalProps.includes(key); }).reduce(function (obj, key) { obj[key] = _this.props[key]; return obj; }, {}); } /** * Get the editor element for the current column. * * @returns {React.ReactElement} React editor component element. */ }, { key: "getLocalEditorElement", value: function getLocalEditorElement() { return getExtendedEditorElement(this.props.children, this.props._getEditorCache(), this.props._columnIndex); } /** * Create the column settings based on the data provided to the `HotColumn` component and it's child components. */ }, { key: "createColumnSettings", value: function createColumnSettings() { var rendererElement = this.props._getChildElementByType(this.props.children, 'hot-renderer'); var editorElement = this.getLocalEditorElement(); this.columnSettings = SettingsMapper.getSettings(this.getSettingsProps()); if (rendererElement !== null) { this.columnSettings.renderer = this.props._getRendererWrapper(rendererElement); this.props._componentRendererColumns.set(this.props._columnIndex, true); } if (editorElement !== null) { this.columnSettings.editor = this.props._getEditorClass(editorElement, this.props._columnIndex); } } /** * Emit the column settings to the parent using a prop passed from the parent. */ }, { key: "emitColumnSettings", value: function emitColumnSettings() { this.props._emitColumnSettings(this.columnSettings, this.props._columnIndex); } /* --------------------------------------- ------- React lifecycle methods ------- --------------------------------------- */ /** * Logic performed after the mounting of the HotColumn component. */ }, { key: "componentDidMount", value: function componentDidMount() { this.createColumnSettings(); this.emitColumnSettings(); } /** * Logic performed after the updating of the HotColumn component. */ }, { key: "componentDidUpdate", value: function componentDidUpdate() { this.createColumnSettings(); this.emitColumnSettings(); } /** * Render the portals of the editors, if there are any. * * @returns {React.ReactElement} */ }, { key: "render", value: function render() { var ownerDocument = this.props._getOwnerDocument(); var editorPortal = createEditorPortal(ownerDocument, this.getLocalEditorElement()); return React__default["default"].createElement(React__default["default"].Fragment, null, editorPortal); } }]); }(React__default["default"].Component); /** * Component class used to manage the renderer component portals. */ var RenderersPortalManager = /*#__PURE__*/function (_React$Component) { function RenderersPortalManager() { var _this; _classCallCheck(this, RenderersPortalManager); _this = _callSuper(this, RenderersPortalManager, arguments); _this.state = { portals: [] }; return _this; } _inherits(RenderersPortalManager, _React$Component); return _createClass(RenderersPortalManager, [{ key: "render", value: function render() { return React__default["default"].createElement(React__default["default"].Fragment, null, this.state.portals); } }]); }(React__default["default"].Component); var version="15.2.0"; function getDefaultExportFromCjs (x) { return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; } var propTypes = {exports: {}}; /** * Copyright (c) 2013-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ var ReactPropTypesSecret_1; var hasRequiredReactPropTypesSecret; function requireReactPropTypesSecret() { if (hasRequiredReactPropTypesSecret) return ReactPropTypesSecret_1; hasRequiredReactPropTypesSecret = 1; var ReactPropTypesSecret = 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED'; ReactPropTypesSecret_1 = ReactPropTypesSecret; return ReactPropTypesSecret_1; } /** * Copyright (c) 2013-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ var factoryWithThrowingShims; var hasRequiredFactoryWithThrowingShims; function requireFactoryWithThrowingShims() { if (hasRequiredFactoryWithThrowingShims) return factoryWithThrowingShims; hasRequiredFactoryWithThrowingShims = 1; var ReactPropTypesSecret = requireReactPropTypesSecret(); function emptyFunction() {} function emptyFunctionWithReset() {} emptyFunctionWithReset.resetWarningCache = emptyFunction; factoryWithThrowingShims = function factoryWithThrowingShims() { function shim(props, propName, componentName, location, propFullName, secret) { if (secret === ReactPropTypesSecret) { // It is still safe when called from React. return; } var err = new Error('Calling PropTypes validators directly is not supported by the `prop-types` package. ' + 'Use PropTypes.checkPropTypes() to call them. ' + 'Read more at http://fb.me/use-check-prop-types'); err.name = 'Invariant Violation'; throw err; } shim.isRequired = shim; function getShim() { return shim; } // Important! // Keep this list in sync with production version in `./factoryWithTypeCheckers.js`. var ReactPropTypes = { array: shim, bigint: shim, bool: shim, func: shim, number: shim, object: shim, string: shim, symbol: shim, any: shim, arrayOf: getShim, element: shim, elementType: shim, instanceOf: getShim, node: shim, objectOf: getShim, oneOf: getShim, oneOfType: getShim, shape: getShim, exact: getShim, checkPropTypes: emptyFunctionWithReset, resetWarningCache: emptyFunction }; ReactPropTypes.PropTypes = ReactPropTypes; return ReactPropTypes; }; return factoryWithThrowingShims; } /** * Copyright (c) 2013-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ { // By explicitly using `prop-types` you are opting into new production behavior. // http://fb.me/prop-types-in-prod propTypes.exports = requireFactoryWithThrowingShims()(); } var propTypesExports = propTypes.exports; var PropTypes = /*@__PURE__*/getDefaultExportFromCjs(propTypesExports); /** * A Handsontable-ReactJS wrapper. * * To implement, use the `HotTable` tag with properties corresponding to Handsontable options. * For example: * * ```js * <HotTable id="hot" data={dataObject} contextMenu={true} colHeaders={true} width={600} height={300} stretchH="all" /> * * // is analogous to * let hot = new Handsontable(document.getElementById('hot'), { * data: dataObject, * contextMenu: true, * colHeaders: true, * width: 600 * height: 300 * }); * * ``` * * @class HotTableCB */ var HotTableClass = /*#__PURE__*/function (_React$Component) { function HotTableClass() { var _this; _classCallCheck(this, HotTableClass); _this = _callSuper(this, HotTableClass, arguments); /** * The `id` of the main Handsontable DOM element. * * @type {String} */ _this.id = null; /** * Reference to the Handsontable instance. * * @private * @type {Object} */ _this.__hotInstance = null; /** * Reference to the main Handsontable DOM element. * * @type {HTMLElement} */ _this.hotElementRef = null; /** * Array of object containing the column settings. * * @type {Array} */ _this.columnSettings = []; /** * Component used to manage the renderer portals. * * @type {React.Component} */ _this.renderersPortalManager = null; /** * Map that stores React portals. * @type {Map<string, React.ReactPortal>} */ _this.portalCache = new Map(); /** * Portal Container Cache * * @private * @type {Map} */ _this.portalContainerCache = new Map(); /** * The rendered cells cache. * * @private * @type {Map} */ _this.renderedCellCache = new Map(); /** * Editor cache. * * @private * @type {Map} */ _this.editorCache = new Map(); /** * Map with column indexes (or a string = 'global') as keys, and booleans as values. Each key represents a component-based editor * declared for the used column index, or a global one, if the key is the `global` string. * * @private * @type {Map} */ _this.componentRendererColumns = new Map(); return _this; } /** * Package version getter. * * @returns The version number of the package. */ _inherits(HotTableClass, _React$Component); return _createClass(HotTableClass, [{ key: "hotInstance", get: /** * Getter for the property storing the Handsontable instance. */ function get() { if (!this.__hotInstance || this.__hotInstance && !this.__hotInstance.isDestroyed) { // Will return the Handsontable instance or `null` if it's not yet been created. return this.__hotInstance; } else { console.warn(HOT_DESTROYED_WARNING); return null; } } /** * Returns `true` if the `hotInstance` exists, but was destroyed. * * @private * @returns {boolean} */, set: /** * Setter for the property storing the Handsontable instance. * @param {Handsontable} hotInstance The Handsontable instance. */ function set(hotInstance) { this.__hotInstance = hotInstance; } /** * Get Portal Container Cache * * @returns {Map} */ }, { key: "_isHotInstanceDestroyed", value: function _isHotInstanceDestroyed() { return this.__hotInstance && this.__hotInstance.isDestroyed; } }, { key: "getPortalContainerCache", value: function getPortalContainerCache() { return this.portalContainerCache; } /** * Get the rendered table cell cache. * * @returns {Map} */ }, { key: "getRenderedCellCache", value: function getRenderedCellCache() { return this.renderedCellCache; } /** * Get the editor cache and return it. * * @returns {Map} */ }, { key: "getEditorCache", value: function getEditorCache() { return this.editorCache; } /** * Clear both the editor and the renderer cache. */ }, { key: "clearCache", value: function clearCache() { this.getRenderedCellCache().clear(); this.componentRendererColumns.clear(); } /** * Get the `Document` object corresponding to the main component element. * * @returns The `Document` object used by the component. */ }, { key: "getOwnerDocument", value: function getOwnerDocument() { if (isCSR()) { return this.hotElementRef ? this.hotElementRef.ownerDocument : document; } return null; } /** * Set the reference to the main Handsontable DOM element. * * @param {HTMLElement} element The main Handsontable DOM element. */ }, { key: "setHotElementRef", value: function setHotElementRef(element) { this.hotElementRef = element; } /** * Return a renderer wrapper function for the provided renderer component. * * @param {React.ReactElement} rendererElement React renderer component. * @returns {Handsontable.renderers.Base} The Handsontable rendering function. */ }, { key: "getRendererWrapper", value: function getRendererWrapper(rendererElement) { var hotTableComponent = this; return function __internalRenderer(instance, TD, row, col, prop, value, cellProperties) { var renderedCellCache = hotTableComponent.getRenderedCellCache(); var portalContainerCache = hotTableComponent.getPortalContainerCache(); var key = "".concat(row, "-").concat(col); // Handsontable.Core type is missing guid var instanceGuid = instance.guid; var portalContainerKey = "".concat(instanceGuid, "-").concat(key); var portalKey = "".concat(key, "-").concat(instanceGuid); if (renderedCellCache.has(key)) { TD.innerHTML = renderedCellCache.get(key).innerHTML; } if (TD && !TD.getAttribute('ghost-table')) { var cachedPortal = hotTableComponent.portalCache.get(portalKey); var cachedPortalContainer = portalContainerCache.get(portalContainerKey); while (TD.firstChild) { TD.removeChild(TD.firstChild); } // if portal already exists, do not recreate if (cachedPortal && cachedPortalContainer) { TD.appendChild(cachedPortalContainer); } else { var _createPortal = createPortal(rendererElement, { TD: TD, row: row, col: col, prop: prop, value: value, cellProperties: cellProperties, isRenderer: true }, TD.ownerDocument, portalKey, cachedPortalContainer), portal = _createPortal.portal, portalContainer = _createPortal.portalContainer; portalContainerCache.set(portalContainerKey, portalContainer); TD.appendChild(portalContainer); hotTableComponent.portalCache.set(portalKey, portal); } } renderedCellCache.set(key, TD); return TD; }; } /** * Create a fresh class to be used as an editor, based on the provided editor React element. * * @param {React.ReactElement} editorElement React editor component. * @param {string|number} [editorColumnScope] The editor scope (column index or a 'global' string). Defaults to * 'global'. * @returns {Function} A class to be passed to the Handsontable editor settings. */ }, { key: "getEditorClass", value: function getEditorClass(editorElement) { var _this$getEditorCache$; var editorColumnScope = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : GLOBAL_EDITOR_SCOPE; var editorClass = getOriginalEditorClass(editorElement); var cachedComponent = (_this$getEditorCache$ = this.getEditorCache().get(editorClass)) === null || _this$getEditorCache$ === void 0 ? void 0 : _this$getEditorCache$.get(editorColumnScope); return this.makeEditorClass(cachedComponent); } /** * Create a class to be passed to the Handsontable's settings. * * @param {React.ReactElement} editorComponent React editor component. * @returns {Function} A class to be passed to the Handsontable editor settings. */ }, { key: "makeEditorClass", value: function makeEditorClass(editorComponent) { var customEditorClass = /*#__PURE__*/function (_Handsontable$editors) { function CustomEditor(hotInstance) { var _this2; _classCallCheck(this, CustomEditor); _this2 = _callSuper(this, CustomEditor, [hotInstance]); editorComponent.hotCustomEditorInstance = _this2; _this2.editorComponent = editorComponent; return _this2; } _inherits(CustomEditor, _Handsontable$editors); return _createClass(CustomEditor, [{ key: "focus", value: function focus() {} }, { key: "getValue", value: function getValue() {} }, { key: "setValue", value: function setValue() {} }, { key: "open", value: function open() {} }, { key: "close", value: function close() {} }]); }(Handsontable__default["default"].editors.BaseEditor); // Fill with the rest of the BaseEditor methods Object.getOwnPropertyNames(Handsontable__default["default"].editors.BaseEditor.prototype).forEach(function (propName) { if (propName === 'constructor') { return; } customEditorClass.prototype[propName] = function () { var _editorComponent$prop; for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } return (_editorComponent$prop = editorComponent[propName]).call.apply(_editorComponent$prop, [editorComponent].concat(args)); }; }); return customEditorClass; } /** * Get the renderer element for the entire HotTable instance. * * @returns {React.ReactElement} React renderer component element. */ }, { key: "getGlobalRendererElement", value: function getGlobalRendererElement() { return getChildElementByType(this.props.children, 'hot-renderer'); } /** * Get the editor element for the entire HotTable instance. * * @param {React.ReactNode} [children] Children of the HotTable instance. Defaults to `this.props.children`. * @returns {React.ReactElement} React editor component element. */ }, { key: "getGlobalEditorElement", value: function getGlobalEditorElement() { return getExtendedEditorElement(this.props.children, this.getEditorCache()); } /** * Create a new settings object containing the column settings and global editors and renderers. * * @param {boolean} [init=false] `true` if called on Handsontable initialization. * @param {HotTableProps} [prevProps] The previous properties object. * @returns {Handsontable.GridSettings} New global set of settings for Handsontable. */ }, { key: "createNewGlobalSettings", value: function createNewGlobalSettings() { var _this$hotInstance; var init = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; var prevProps = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var initOnlySettingKeys = !this._isHotInstanceDestroyed() ? // Needed for React's double-rendering. ((_this$hotInstance = this.hotInstance) === null || _this$hotInstance === void 0 || (_this$hotInstance = _this$hotInstance.getSettings()) === null || _this$hotInstance === void 0 ? void 0 : _this$hotInstance._initOnlySettings) || [] : []; var newSettings = SettingsMapper.getSettings(this.props, { prevProps: prevProps, isInit: init, initOnlySettingKeys: initOnlySettingKeys }); var globalRendererNode = this.getGlobalRendererElement(); var globalEditorNode = this.getGlobalEditorElement(); newSettings.columns = this.columnSettings.length ? this.columnSettings : newSettings.columns; if (globalEditorNode) { newSettings.editor = this.getEditorClass(globalEditorNode, GLOBAL_EDITOR_SCOPE); } else { var _this$props$settings; if (this.props.editor || (_this$props$settings = this.props.settings) !== null && _this$props$settings !== void 0 && _this$props$settings.editor) { newSettings.editor = this.props.editor || this.props.settings.editor; } else { newSettings.editor = registry.getEditor('text'); } } if (globalRendererNode) { newSettings.renderer = this.getRendererWrapper(globalRendererNode); this.componentRendererColumns.set('global', true); } else { var _this$props$settings2; if (this.props.renderer || (_this$props$settings2 = this.props.settings) !== null && _this$props$settings2 !== void 0 && _this$props$settings2.renderer) { newSettings.renderer = this.props.renderer || this.props.settings.renderer; } else { newSettings.renderer = registry$1.getRenderer('text'); } } return newSettings; } /** * Detect if `autoRowSize` or `autoColumnSize` is defined, and if so, throw an incompatibility warning. * * @param {Handsontable.GridSettings} newGlobalSettings New global settings passed as Handsontable config. */ }, { key: "displayAutoSizeWarning", value: function displayAutoSizeWarning(newGlobalSettings) { var _this$hotInstance$get, _this$hotInstance$get2; if (this.hotInstance && ((_this$hotInstance$get = this.hotInstance.getPlugin('autoRowSize')) !== null && _this$hotInstance$get !== void 0 && _this$hotInstance$get.enabled || (_this$hotInstance$get2 = this.hotInstance.getPlugin('autoColumnSize')) !== null && _this$hotInstance$get2 !== void 0 && _this$hotInstance$get2.enabled)) { if (this.componentRendererColumns.size > 0) { warn(AUTOSIZE_WARNING); } } } /** * Sets the column settings based on information received from HotColumn. * * @param {HotTableProps} columnSettings Column settings object. * @param {Number} columnIndex Column index. */ }, { key: "setHotColumnSettings", value: function setHotColumnSettings(columnSettings, columnIndex) { this.columnSettings[columnIndex] = columnSettings; } /** * Handsontable's `beforeViewRender` hook callback. */ }, { key: "handsontableBeforeViewRender", value: function handsontableBeforeViewRender() { this.portalCache.clear(); this.getRenderedCellCache().clear(); } /** * Handsontable's `afterViewRender` hook callback. */ }, { key: "handsontableAfterViewRender", value: function handsontableAfterViewRender() { this.renderersPortalManager.setState({ portals: _toConsumableArray(this.portalCache.values()) }); } /** * Call the `updateSettings` method for the Handsontable instance. * * @param {Object} newSettings The settings object. */ }, { key: "updateHot", value: function updateHot(newSettings) { if (this.hotInstance) { this.hotInstance.updateSettings(newSettings, false); } } /** * Set the renderers portal manager ref. * * @param {React.ReactComponent} pmComponent The PortalManager component. */ }, { key: "setRenderersPortalManagerRef", value: function setRenderersPortalManagerRef(pmComponent) { this.renderersPortalManager = pmComponent; } /* --------------------------------------- ------- React lifecycle methods ------- --------------------------------------- */ /** * Initialize Handsontable after the component has mounted. */ }, { key: "componentDidMount", value: function componentDidMount() { var _this3 = this; var newGlobalSettings = this.createNewGlobalSettings(true); this.hotInstance = new Handsontable__default["default"].Core(this.hotElementRef, newGlobalSettings); this.hotInstance.addHook('beforeViewRender', function () { return _this3.handsontableBeforeViewRender(); }); this.hotInstance.addHook('afterViewRender', function () { return _this3.handsontableAfterViewRender(); }); // `init` missing in Handsontable's type definitions. this.hotInstance.init(); this.displayAutoSizeWarning(newGlobalSettings); } /** * Logic performed after the component update. */ }, { key: "componentDidUpdate", value: function componentDidUpdate(prevProps) { this.clearCache(); var newGlobalSettings = this.createNewGlobalSettings(false, prevProps); this.updateHot(newGlobalSettings); this.displayAutoSizeWarning(newGlobalSettings); } /** * Destroy the Handsontable instance when the parent component unmounts. */ }, { key: "componentWillUnmount", value: function componentWillUnmount() { this.clearCache(); if (this.hotInstance) { this.hotInstance.destroy(); } } /** * Render the component. */ }, { key: "render", value: function render() { var _this4 = this; var isHotColumn = function isHotColumn(childNode) { return childNode.type === HotColumn; }; var children = React__default["default"].Children.toArray(this.props.children); // clone the HotColumn nodes and extend them with the callbacks var hotColumnClones = children.filter(function (childNode) { return isHotColumn(childNode); }).map(function (childNode, columnIndex) { return React__default["default"].cloneElement(childNode, { _componentRendererColumns: _this4.componentRendererColumns, _emitColumnSettings: _this4.setHotColumnSettings.bind(_this4), _columnIndex: columnIndex, _getChildElementByType: getChildElementByType.bind(_this4), _getRendererWrapper: _this4.getRendererWrapper.bind(_this4), _getEditorClass: _this4.getEditorClass.bind(_this4), _getOwnerDocument: _this4.getOwnerDocument.bind(_this4), _getEditorCache: _this4.getEditorCache.bind(_this4), children: childNode.props.children }); }); var containerProps = getContainerAttributesProps(this.props); var editorPortal = createEditorPortal(this.getOwnerDocument(), this.getGlobalEditorElement()); return React__default["default"].createElement(React__default["default"].Fragment, null, React__default["default"].createElement("div", Object.assign({ ref: this.setHotElementRef.bind(this) }, containerProps), hotColumnClones), React__default["default"].createElement(RenderersPortalManager, { ref: this.setRenderersPortalManagerRef.bind(this) }), editorPortal); } }], [{ key: "version", get: function get() { return version; } }]); }(React__default["default"].Component); /** * Prop types to be checked at runtime. */ HotTableClass.propTypes = { style: PropTypes.object, id: PropTypes.string, className: PropTypes.string }; var _excluded = ["children"]; // Use global React variable for `forwardRef` access (React 16 support) var HotTable = React__default["default"].forwardRef(function (_ref, ref) { var _props$id; var children = _ref.children, props = _objectWithoutProperties(_ref, _excluded); var generatedId = typeof React__default["default"].useId === 'function' ? React__default["default"].useId() : undefined; var componentId = (_props$id = props.id) !== null && _props$id !== void 0 ? _props$id : generatedId; return React__default["default"].createElement(HotTableClass, Object.assign({ id: componentId }, props, { ref: ref }), children); }); HotTable.version = HotTableClass.version; var BaseEditorComponent = /*#__PURE__*/function (_React$Component) { function BaseEditorComponent() { var _this; _classCallCheck(this, BaseEditorComponent); _this = _callSuper(this, BaseEditorComponent, arguments); _this.name = 'BaseEditorComponent'; _this.instance = null; _this.row = null; _this.col = null; _this.prop = null; _this.TD = null; _this.originalValue = null; _this.cellProperties = null; _this.state = null; _this.hotInstance = null; _this.hotCustomEditorInstance = null; _this.hot = null; return _this; } _inherits(BaseEditorComponent, _React$Component); return _createClass(BaseEditorComponent, [{ key: "componentDidMount", value: function componentDidMount() { if (this.props.emitEditorInstance) { this.props.emitEditorInstance(this, this.props.editorColumnScope); } } }, { key: "componentDidUpdate", value: function componentDidUpdate() { if (this.props.emitEditorInstance) { this.props.emitEditorInstance(this, this.props.editorColumnScope); } } // BaseEditor methods: }, { key: "_fireCallbacks", value: function _fireCallbacks() { var _Handsontable$editors; for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } (_Handsontable$editors = Handsontable__default["default"].editors.BaseEditor.prototype._fireCallbacks).call.apply(_Handsontable$editors, [this.hotCustomEditorInstance].concat(args)); } }, { key: "beginEditing", value: function beginEditing() { var _Handsontable$editors2; for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { args[_key2] = arguments[_key2]; } return (_Handsontable$editors2 = Handsontable__default["default"].editors.BaseEditor.prototype.beginEditing).call.apply(_Handsontable$editors2, [this.hotCustomEditorInstance].concat(args)); } }, { key: "cancelChanges", value: function cancelChanges() { var _Handsontable$editors3; for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { args[_key3] = arguments[_key3]; } return (_Handsontable$editors3 = Handsontable__default["default"].editors.BaseEditor.prototype.cancelChanges).call.apply(_Handsontable$editors3, [this.hotCustomEditorInstance].concat(args)); } }, { key: "checkEditorSection", value: function checkEditorSection() { var _Handsontable$editors4; for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { args[_key4] = arguments[_key4]; } return (_Handsontable$editors4 = Handsontable__default["default"].editors.BaseEditor.prototype.checkEditorSection).call.apply(_Handsontable$editors4, [this.hotCustomEditorInstance].concat(args)); } }, { key: "close", value: function close() { var _Handsontable$editors5; for (var _len5 = arguments.length, args = new Array(_len5), _key5 = 0; _key5 < _len5; _key5++) { args[_key5] = arguments[_key5]; } return (_Handsontable$editors5 = Handsontable__default["default"].editors.BaseEditor.prototype.close).call.apply(_Handsontable$editors5, [this.hotCustomEditorInstance].concat(args)); } }, { key: "discardEditor", value: function discardEditor() { var _Handsontable$editors6; for (var _len6 = arguments.length, args = new Array(_len6), _key6 = 0; _key6 < _len6; _key6++) { args[_key6] = arguments[_key6]; } return (_Handsontable$editors6 = Handsontable__default["default"].editors.BaseEditor.prototype.discardEditor).call.apply(_Handsontable$editors6, [this.hotCustomEditorInstance].concat(args)); } }, { key: "enableFullEditMode", value: function enableFullEditMode() { var _Handsontable$editors7; for (var _len7 = arguments.length, args = new Array(_len7), _key7 = 0; _key7 < _len7; _key7++) { args[_key7] = arguments[_key7]; } return (_Handsontable$editors7 = Handsontable__default["default"].editors.BaseEditor.prototype.enableFullEditMode).call.apply(_Handsontable$editors7, [this.hotCustomEditorInstance].concat(args)); } }, { key: "extend", value: function extend() { var _Handsontable$editors8; for (var _len8 = arguments.length, args = new Array(_len8), _key8 = 0; _key8 < _len8; _key8++) { args[_key8] = arguments[_key8]; } return (_Handsontable$editors8 = Handsontable__default["default"].editors.BaseEditor.prototype.extend).call.apply(_Handsontable$editors8, [this.hotCustomEditorInstance].concat(args)); } }, { key: "finishEditing", value: function finishEditing() { var _Handsontable$editors9; for (var _len9 = arguments.length, args = new Array(_len9), _key9 = 0; _k